Repository: gethinode/hinode Branch: main Commit: 01357a2c7eea Files: 453 Total size: 842.2 KB Directory structure: gitextract_pae652cm/ ├── .eslintrc.yml ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── feature_request.md │ ├── codeql/ │ │ └── codeql-config.yml │ ├── dependabot.yml │ ├── release.yml │ └── workflows/ │ ├── auto-merge.yml │ ├── codeql.yml │ ├── lint-build.yml │ ├── mod-update.yml │ └── release.yml ├── .gitignore ├── .gitmodules ├── .husky/ │ ├── commit-msg │ ├── install.mjs │ └── pre-commit ├── .markdownlint-cli2.jsonc ├── .stylelintignore ├── .stylelintrc.json ├── CLAUDE.md ├── LICENSE ├── README.md ├── archetypes/ │ └── default.md ├── assets/ │ ├── js/ │ │ ├── alert.js │ │ ├── animation.js │ │ ├── clipboard.js │ │ ├── critical/ │ │ │ ├── _cookie.js │ │ │ ├── color.js │ │ │ ├── languageSelector.js │ │ │ └── sidebar-pre-init.js │ │ ├── menu.js │ │ ├── modal.js │ │ ├── nav.js │ │ ├── navbar.js │ │ ├── optional/ │ │ │ └── .gitkeep │ │ ├── popover.js │ │ ├── sharing.js │ │ ├── sidebar-group.js │ │ ├── sidebar-toggle.js │ │ ├── testimonial.js │ │ ├── toast.js │ │ ├── toc.js │ │ ├── tooltip.js │ │ ├── vendor/ │ │ │ └── .gitkeep │ │ └── video.js │ └── scss/ │ ├── app-dart.scss │ ├── app.scss │ ├── common/ │ │ ├── _animation.scss │ │ ├── _export.scss │ │ ├── _icons.scss │ │ ├── _masonry.scss │ │ ├── _scrollbar.scss │ │ ├── _styles.scss │ │ ├── _utilities-custom.scss │ │ ├── _utilities-responsive.scss │ │ ├── _variables-dark.scss │ │ ├── _variables-dart.scss │ │ └── _variables.scss │ ├── components/ │ │ ├── _abbr.scss │ │ ├── _alert.scss │ │ ├── _blockquote.scss │ │ ├── _button.scss │ │ ├── _card.scss │ │ ├── _carousel.scss │ │ ├── _clipboard.scss │ │ ├── _command.scss │ │ ├── _docs.scss │ │ ├── _feature.scss │ │ ├── _footer.scss │ │ ├── _img.scss │ │ ├── _kbd.scss │ │ ├── _nav.scss │ │ ├── _navbar.scss │ │ ├── _pagination.scss │ │ ├── _persona.scss │ │ ├── _popover.scss │ │ ├── _sidebar.scss │ │ ├── _syntax-dark.scss │ │ ├── _syntax-dart.scss │ │ ├── _syntax-light.scss │ │ ├── _syntax.scss │ │ ├── _table.scss │ │ ├── _testimonial.scss │ │ ├── _timeline.scss │ │ ├── _toast.scss │ │ ├── _toc.scss │ │ ├── _tooltip.scss │ │ └── _video.scss │ ├── helpers/ │ │ ├── _colored-links.scss │ │ └── _display.scss │ ├── layouts/ │ │ ├── _reboot.scss │ │ └── _type.scss │ ├── theme/ │ │ ├── _variables.scss │ │ ├── base.scss │ │ ├── fonts.scss │ │ └── theme.scss │ └── vendor/ │ └── .gitkeep ├── commitlint.config.js ├── config/ │ ├── _default/ │ │ ├── hugo.toml │ │ ├── languages.toml │ │ ├── markup.toml │ │ ├── menus/ │ │ │ └── menus.en.toml │ │ ├── params.toml │ │ └── server.toml │ ├── ci/ │ │ └── hugo.toml │ ├── development/ │ │ └── params.toml │ ├── postcss.config.js │ └── production/ │ ├── deployment.toml │ ├── hugo.toml │ └── params.toml ├── content/ │ ├── _index.md │ └── _modals/ │ └── _index.md ├── data/ │ ├── .gitkeep │ ├── dimensions.yml │ ├── netlify.toml │ ├── server.toml │ └── structures/ │ ├── abbr.yml │ ├── accordion-item.yml │ ├── accordion.yml │ ├── alert.yml │ ├── args.yml │ ├── background.yml │ ├── badge.yml │ ├── breadcrumb.yml │ ├── button-group.yml │ ├── button.yml │ ├── card-group.yml │ ├── card-icon.yml │ ├── card.yml │ ├── carousel-item.yml │ ├── carousel.yml │ ├── collapse.yml │ ├── command.yml │ ├── docs.yml │ ├── download.yml │ ├── example.yml │ ├── featured-illustration.yml │ ├── file.yml │ ├── form-hook.yml │ ├── get-dimension.yml │ ├── hero-image.yml │ ├── image-adapter-rewrite.yml │ ├── image-adapter.yml │ ├── image-definition.yml │ ├── image-dimension.yml │ ├── image-rewrite.yml │ ├── image-set.yml │ ├── image.yml │ ├── ins.yml │ ├── kbd.yml │ ├── link.yml │ ├── links.yml │ ├── list.yml │ ├── live-pages.yml │ ├── mark.yml │ ├── menu-item.yml │ ├── nav-item.yml │ ├── nav.yml │ ├── navbar-item.yml │ ├── navbar.yml │ ├── page-alert.yml │ ├── pagination.yml │ ├── persona.yml │ ├── release.yml │ ├── script.yml │ ├── scripts.yml │ ├── section-header.yml │ ├── section-menu.yml │ ├── section-title.yml │ ├── sidebar.yml │ ├── spinner.yml │ ├── stack.yml │ ├── sub.yml │ ├── sup.yml │ ├── table.yml │ ├── testimonial.yml │ ├── timeline.yml │ ├── toast.yml │ ├── toc.yml │ ├── tooltip.yml │ ├── version.yml │ └── video.yml ├── eslint.config.mjs ├── exampleSite/ │ ├── .gitignore │ ├── config/ │ │ ├── _default/ │ │ │ ├── hugo.toml │ │ │ ├── languages.toml │ │ │ ├── markup.toml │ │ │ ├── menus/ │ │ │ │ ├── menus.en.toml │ │ │ │ ├── menus.fr.toml │ │ │ │ └── menus.nl.toml │ │ │ ├── netlify.toml │ │ │ ├── params.fr.toml │ │ │ ├── params.nl.toml │ │ │ ├── params.toml │ │ │ └── server.toml │ │ ├── ci/ │ │ │ └── hugo.toml │ │ ├── development/ │ │ │ └── params.toml │ │ └── postcss.config.js │ ├── content/ │ │ ├── en/ │ │ │ ├── _index.md │ │ │ ├── about.md │ │ │ ├── blog/ │ │ │ │ ├── _index.md │ │ │ │ ├── first-post.md │ │ │ │ ├── fourth-post.md │ │ │ │ ├── second-post.md │ │ │ │ └── third-post.md │ │ │ ├── browserconfig.md │ │ │ ├── cookies.md │ │ │ ├── privacy.md │ │ │ └── team/ │ │ │ ├── _content.gotmpl │ │ │ └── _index.en.md │ │ ├── fr/ │ │ │ ├── _index.md │ │ │ ├── about.md │ │ │ ├── blog/ │ │ │ │ ├── _index.md │ │ │ │ ├── first-post.md │ │ │ │ ├── fourth-post.md │ │ │ │ ├── second-post.md │ │ │ │ └── third-post.md │ │ │ ├── browserconfig.md │ │ │ ├── cookies.md │ │ │ └── privacy.md │ │ └── nl/ │ │ ├── _index.md │ │ ├── about.md │ │ ├── blog/ │ │ │ ├── _index.md │ │ │ ├── first-post.md │ │ │ ├── fourth-post.md │ │ │ ├── second-post.md │ │ │ └── third-post.md │ │ ├── browserconfig.md │ │ ├── cookies.md │ │ └── privacy.md │ ├── data/ │ │ └── server.toml │ ├── go.mod │ ├── go.sum │ ├── hinode.work │ ├── hinode.work.sum │ ├── hugo_stats.json │ └── layouts/ │ └── _partials/ │ ├── footer/ │ │ └── footer.html │ └── templates/ │ └── script.html ├── go.mod ├── go.sum ├── hugo_stats.json ├── i18n/ │ ├── de.yaml │ ├── en.yaml │ ├── fr.yaml │ ├── nl.yaml │ ├── pl.yaml │ ├── pt-br.yaml │ ├── zh-hans.yaml │ └── zh-hant.yaml ├── layouts/ │ ├── 404.html │ ├── _markup/ │ │ ├── render-blockquote.html │ │ ├── render-codeblock-math.html │ │ ├── render-codeblock.html │ │ ├── render-heading.html │ │ ├── render-image.html │ │ ├── render-link.html │ │ ├── render-passthrough.html │ │ └── render-table.html │ ├── _partials/ │ │ ├── assets/ │ │ │ ├── adapters/ │ │ │ │ ├── cloudinary.html │ │ │ │ ├── hugo.html │ │ │ │ ├── imagekit-rewrite.html │ │ │ │ ├── imagekit.html │ │ │ │ └── imgix.html │ │ │ ├── args.html │ │ │ ├── breadcrumb.html │ │ │ ├── button.html │ │ │ ├── card-group.html │ │ │ ├── card-icon.html │ │ │ ├── card.html │ │ │ ├── carousel-item.html │ │ │ ├── download.html │ │ │ ├── featured-illustration.html │ │ │ ├── helpers/ │ │ │ │ ├── GetDimension.html │ │ │ │ ├── image-definition.html │ │ │ │ ├── image-dimension.html │ │ │ │ ├── image-rewrite.html │ │ │ │ ├── image-set.html │ │ │ │ ├── navbar-item.html │ │ │ │ ├── navbar-languages.html │ │ │ │ ├── navbar-mode.html │ │ │ │ ├── navbar-render-menu.html │ │ │ │ ├── navbar-versions.html │ │ │ │ └── sidebar-menu-entry.html │ │ │ ├── hero-image.html │ │ │ ├── image.html │ │ │ ├── link.html │ │ │ ├── links.html │ │ │ ├── live-card.html │ │ │ ├── live-image.html │ │ │ ├── live-pages.html │ │ │ ├── menu-item.html │ │ │ ├── modals.html │ │ │ ├── nav-item.html │ │ │ ├── nav.html │ │ │ ├── navbar.html │ │ │ ├── page-alert.html │ │ │ ├── pagination.html │ │ │ ├── persona.html │ │ │ ├── section-title.html │ │ │ ├── sidebar.html │ │ │ ├── spinner.html │ │ │ ├── stack.html │ │ │ ├── table.html │ │ │ ├── testimonial.html │ │ │ ├── timeline.html │ │ │ ├── toast.html │ │ │ ├── toc-dropdown.html │ │ │ ├── toc-headings.html │ │ │ ├── toc-main.html │ │ │ ├── toc-parse-content.html │ │ │ ├── toc.html │ │ │ ├── version.html │ │ │ └── video.html │ │ ├── footer/ │ │ │ ├── footer.html │ │ │ ├── scripts.html │ │ │ ├── social.html │ │ │ └── toast-container.html │ │ ├── head/ │ │ │ ├── favicon.html │ │ │ ├── head.html │ │ │ ├── icons.html │ │ │ ├── opengraph.html │ │ │ ├── seo.html │ │ │ ├── structured-data.html │ │ │ ├── stylesheet-core.html │ │ │ ├── stylesheet.html │ │ │ └── twitter_cards.html │ │ ├── page/ │ │ │ ├── articles.html │ │ │ ├── blocks.html │ │ │ ├── metadata.html │ │ │ ├── navbar-extra.html │ │ │ ├── navigation.html │ │ │ ├── sharing.html │ │ │ ├── sidebar-offcanvas.html │ │ │ ├── sidebar.html │ │ │ ├── tags.html │ │ │ ├── taxonomy-list.html │ │ │ ├── taxonomy-tag.html │ │ │ └── thumbnail.html │ │ ├── templates/ │ │ │ └── script.html │ │ └── utilities/ │ │ ├── AddModule.html │ │ ├── GetBackgroundStyle.html │ │ ├── GetIllustration.html │ │ ├── GetIncludeTOC.html │ │ ├── GetLink.html │ │ ├── GetMetadata.html │ │ ├── GetSharing.html │ │ ├── InitModules.html │ │ └── git.html │ ├── _shortcodes/ │ │ ├── abbr.html │ │ ├── abbr.md │ │ ├── accordion-item.html │ │ ├── accordion-item.md │ │ ├── accordion.html │ │ ├── accordion.md │ │ ├── alert.html │ │ ├── alert.md │ │ ├── args.html │ │ ├── args.md │ │ ├── badge.html │ │ ├── badge.md │ │ ├── breadcrumb.html │ │ ├── breadcrumb.md │ │ ├── button-group.html │ │ ├── button-group.md │ │ ├── button.html │ │ ├── button.md │ │ ├── card-group.html │ │ ├── card-group.md │ │ ├── card.html │ │ ├── card.md │ │ ├── carousel.html │ │ ├── carousel.md │ │ ├── collapse.html │ │ ├── collapse.md │ │ ├── command.html │ │ ├── command.md │ │ ├── docs.html │ │ ├── docs.md │ │ ├── example-bookshop.html │ │ ├── example-bookshop.md │ │ ├── example.html │ │ ├── example.md │ │ ├── file.html │ │ ├── file.md │ │ ├── image.html │ │ ├── image.md │ │ ├── img.html │ │ ├── img.md │ │ ├── ins.html │ │ ├── ins.md │ │ ├── kbd.html │ │ ├── kbd.md │ │ ├── link.html │ │ ├── link.md │ │ ├── mark.html │ │ ├── mark.md │ │ ├── nav-item.html │ │ ├── nav-item.md │ │ ├── nav.html │ │ ├── nav.md │ │ ├── navbar.html │ │ ├── navbar.md │ │ ├── persona.html │ │ ├── persona.md │ │ ├── release.html │ │ ├── release.md │ │ ├── spinner.html │ │ ├── spinner.md │ │ ├── sub.html │ │ ├── sub.md │ │ ├── sup.html │ │ ├── sup.md │ │ ├── table.html │ │ ├── table.md │ │ ├── testimonial.html │ │ ├── testimonial.md │ │ ├── timeline.html │ │ ├── timeline.md │ │ ├── toast.html │ │ ├── toast.md │ │ ├── tooltip.html │ │ ├── tooltip.md │ │ ├── video.html │ │ ├── video.md │ │ ├── vimeo.html │ │ ├── vimeo.md │ │ ├── youtube.html │ │ └── youtube.md │ ├── alias.html │ ├── baseof.html │ ├── baseof.xml │ ├── body.html │ ├── docs/ │ │ ├── all.html │ │ ├── body.html │ │ ├── footer.html │ │ └── header.html │ ├── footer.html │ ├── form/ │ │ └── single.html │ ├── header.html │ ├── index.redir │ ├── list.html │ ├── minimal/ │ │ ├── body.html │ │ ├── footer.html │ │ └── header.html │ ├── robots.txt │ ├── single.html │ ├── single.xml │ ├── tags/ │ │ └── list.html │ └── toc.html ├── netlify.toml ├── package.json ├── static/ │ └── js/ │ └── alias.js └── theme.toml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .eslintrc.yml ================================================ env: browser: true es6: true extends: - standard globals: Atomics: readonly SharedArrayBuffer: readonly parserOptions: ecmaVersion: 2018 sourceType: module rules: {} ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: "[BUG]" labels: bug assignees: '' --- ## Describe the bug A clear and concise description of what the bug is. ## To reproduce Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error Alternatively, include the commands from your terminal as bash script. ## Expected behavior If applicable, a clear and concise description of what you expected to happen. ## Log file If applicable, add a copy of Hugo's log messages. ## Screenshots If applicable, add screenshots to help explain your problem. ## Host environment Please complete the following information where applicable. - Hinode version: [e.g. v0.11.3] - Host OS: [e.g. macOS Ventura 13.3] - Node version: [e.g. node v18.15.0] - Browser: [e.g. Google Chrome Version 108.0.5359.124 (Official Build) (arm64)] ## Hugo environment Copy the output of `hugo env` or `npm run env` here. ```bash [env output] ``` ## Additional context Add any other context about the problem here. ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project title: '' labels: enhancement assignees: '' --- ## Problem or enhancement idea A clear and concise description of what the problem is. E.g. I'm always frustrated when ... Or else, the enhancement idea to further improve Hinode. ## Proposed solution A clear and concise description of what you want to happen. ## Alternatives A clear and concise description of any alternative solutions or features you've considered. ## Additional context Add any other context or screenshots about the feature request here. ================================================ FILE: .github/codeql/codeql-config.yml ================================================ paths: - 'assets/js' paths-ignore: - '**/vendor' - '**/critical/languageSelector.js' - '**/critical/color.js' - '**/clipboard.js' - '**/navbar.js' - '**/sharing.js' ================================================ FILE: .github/dependabot.yml ================================================ # Please see the documentation for all configuration options: # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" open-pull-requests-limit: 10 - package-ecosystem: "npm" directory: "/" schedule: interval: "daily" versioning-strategy: increase ================================================ FILE: .github/release.yml ================================================ changelog: exclude: labels: - skip-changelog categories: - title: ❗ Breaking Changes labels: - Semver-Major - breaking-change - title: 🚀 Highlights labels: - release-highlight - title: 🎉 New Features labels: - Semver-Minor - enhancement - title: 🐛 Bug Fixes labels: - fix - bugfix - bug - title: 📦 Dependencies labels: - dependencies - title: 🧰 Other Changes labels: - "*" ================================================ FILE: .github/workflows/auto-merge.yml ================================================ # Source: https://nicolasiensen.github.io/2022-07-23-automating-dependency-updates-with-dependabot-github-auto-merge-and-github-actions/ name: Dependabot auto-merge on: pull_request_target permissions: pull-requests: write contents: write jobs: review-dependabot-pr: runs-on: ubuntu-latest if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }} steps: - name: Dependabot metadata id: metadata uses: dependabot/fetch-metadata@v3 with: github-token: "${{ secrets.GITHUB_TOKEN }}" - name: Enable auto-merge for Dependabot PRs run: gh pr merge --auto --merge "$PR_URL" env: PR_URL: ${{github.event.pull_request.html_url}} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - name: Approve patch and minor updates if: ${{steps.dependabot-metadata.outputs.update-type == 'version-update:semver-patch' || steps.dependabot-metadata.outputs.update-type == 'version-update:semver-minor'}} run: gh pr review $PR_URL --approve -b "I'm **approving** this pull request because **it includes a patch or minor update**" env: PR_URL: ${{github.event.pull_request.html_url}} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - name: Comment on major updates of any dependencies if: ${{steps.dependabot-metadata.outputs.update-type == 'version-update:semver-major'}} run: | gh pr comment $PR_URL --body "I'm **not approving** this PR because **it includes a major update of a dependency**" gh pr edit $PR_URL --add-label "requires-manual-qa" env: PR_URL: ${{github.event.pull_request.html_url}} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} ================================================ FILE: .github/workflows/codeql.yml ================================================ # For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. # # ******** NOTE ******** # We have attempted to detect the languages in your repository. Please check # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # name: "CodeQL Advanced" on: push: branches: [ "main" ] pull_request: branches: [ "main" ] schedule: - cron: '44 1 * * 3' jobs: analyze: name: Analyze (${{ matrix.language }}) # Runner size impacts CodeQL analysis time. To learn more, please see: # - https://gh.io/recommended-hardware-resources-for-running-codeql # - https://gh.io/supported-runners-and-hardware-resources # - https://gh.io/using-larger-runners (GitHub.com only) # Consider using larger runners or machines with greater resources for possible analysis time improvements. runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} permissions: # required for all workflows security-events: write # required to fetch internal or private CodeQL packs packages: read # only required for workflows in private repositories actions: read contents: read strategy: fail-fast: false matrix: include: - language: actions build-mode: none - language: javascript-typescript build-mode: none # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift' # Use `c-cpp` to analyze code written in C, C++ or both # Use 'java-kotlin' to analyze code written in Java, Kotlin or both # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages steps: - name: Checkout repository uses: actions/checkout@v6 # Add any setup steps before running the `github/codeql-action/init` action. # This includes steps like installing compilers or runtimes (`actions/setup-node` # or others). This is typically only required for manual builds. # - name: Setup runtime (example) # uses: actions/setup-example@v1 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} config-file: ./.github/codeql/codeql-config.yml # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # queries: security-extended,security-and-quality # If the analyze step fails for one of the languages you are analyzing with # "We were unable to automatically build your code", modify the matrix above # to set the build mode to "manual" for that language. Then modify this step # to build your code. # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - if: matrix.build-mode == 'manual' shell: bash run: | echo 'If you are using a "manual" build mode for one or more of the' \ 'languages you are analyzing, replace this with the commands to build' \ 'your code, for example:' echo ' make bootstrap' echo ' make release' exit 1 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v4 with: category: "/language:${{matrix.language}}" ================================================ FILE: .github/workflows/lint-build.yml ================================================ name: Lint & build on: workflow_dispatch: push: tags: - v* branches: [ main, beta ] pull_request: branches: [ main, beta ] env: CACHE_KEY: 'hugo-hinode' permissions: pull-requests: read contents: read jobs: lint: runs-on: ubuntu-latest steps: - name: Check out repository uses: actions/checkout@v6 - name: Set up Node.js uses: actions/setup-node@v6 with: node-version: lts/* cache: 'npm' cache-dependency-path: '**/package-lock.json' # [24/AUG/23] Adjusted from npm ci to prevent EBADPLATFORM error due to fsevents - name: Install npm run: npm i - name: Lint the source files run: npm run lint build: needs: lint strategy: matrix: os: [macos-latest, windows-latest, ubuntu-latest] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ node-version: [22.x, 24.x] include: - os: ubuntu-latest hugo_cachedir: '/tmp/hugo_cache_runner' - os: macos-latest hugo_cachedir: '/Users/runner/Library/Caches/hugo_cache' - os: windows-latest hugo_cachedir: '~\AppData\Local\hugo_cache' runs-on: ${{ matrix.os }} env: HUGO_CACHEDIR: ${{ matrix.hugo_cachedir }} steps: - name: Check out repository uses: actions/checkout@v6 - name: Install Go uses: actions/setup-go@v6 with: go-version: "stable" - name: Set up Node.js ${{ matrix.node-version }} uses: actions/setup-node@v6 with: node-version: ${{ matrix.node-version }} cache: 'npm' cache-dependency-path: '**/package-lock.json' - name: Install Dart Sass env: DART_SASS_VERSION: "1.98.0" run: | if [ "$RUNNER_OS" == "Linux" ]; then curl -fsSL "https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz" \ | tar -xz -C "$HOME" echo "$HOME/dart-sass" >> $GITHUB_PATH elif [ "$RUNNER_OS" == "macOS" ]; then ARCH=$(uname -m) if [ "$ARCH" == "arm64" ]; then SASS_ARCH="macos-arm64" else SASS_ARCH="macos-x64" fi curl -fsSL "https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-${SASS_ARCH}.tar.gz" \ | tar -xz -C "$HOME" echo "$HOME/dart-sass" >> $GITHUB_PATH elif [ "$RUNNER_OS" == "Windows" ]; then choco install sass fi shell: bash # [24/AUG/23] Adjusted from npm ci for non-macOS to prevent EBADPLATFORM error due to fsevents - name: Perform clean install of npm run: | if [ "$RUNNER_OS" == "macOS" ]; then npm ci else npm i fi shell: bash # On Windows, HUGO_CACHEDIR is initialised from the matrix as '~\AppData\Local\hugo_cache'. # Hugo requires an absolute path, so expand ~ to %LOCALAPPDATA% before using the cache. - name: Expand Hugo cache directory on Windows if: runner.os == 'Windows' run: echo "HUGO_CACHEDIR=$env:LOCALAPPDATA\hugo_cache" >> $env:GITHUB_ENV shell: pwsh # Cache Hugo cachedir and resourcedir (configured in config/ci/hugo.toml) for each OS. # Rolling key restores the previous snapshot as a warm start, then saves a fresh one after build. # No additional content-based invalidation is needed; Hugo uses checksums itself. - name: Use Hugo cache uses: actions/cache@v5 with: path: ${{ env.HUGO_CACHEDIR }} key: ${{ runner.os }}-${{ env.CACHE_KEY }}-${{ github.run_id }} restore-keys: | ${{ runner.os }}-${{ env.CACHE_KEY }}- - name: Display environment run: npm run env - name: Build main site run: npm run build:cache # The example site is to be published to demo.gethinode.com - name: Build example site run: npm run build:example:ci ================================================ FILE: .github/workflows/mod-update.yml ================================================ name: Update Hugo dependencies on: workflow_dispatch: schedule: - cron: '0 3 * * *' # run daily at 03:00 AM permissions: contents: write pull-requests: write jobs: update-mod: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v6 - name: Setup Node.js uses: actions/setup-node@v6 with: node-version: lts/* cache: 'npm' cache-dependency-path: '**/package-lock.json' # [26/AUG/23] Adjusted from npm ci to prevent EBADPLATFORM error due to fsevents - name: Install npm run: npm i - name: Update Hugo module dependencies id: mod-updates run: | MOD_OUTPUT=$(npm run mod:update 2>&1) echo "$MOD_OUTPUT" MOD_UPDATES=$(echo "$MOD_OUTPUT" | grep '^go: upgraded' | sed 's/go: / - /' | sort -u) echo 'MOD_UPDATES<> $GITHUB_OUTPUT echo "$MOD_UPDATES" >> "$GITHUB_OUTPUT" echo 'EOF' >> $GITHUB_OUTPUT - name: Create Pull Request uses: gethinode-actions/create-pull-request@v8 with: token: ${{ secrets.HUGO_MOD_PR }} commit-message: 'fix: update Hugo module dependencies' committer: GitHub branch: hugo-mod-dependencies delete-branch: true title: 'Update Hugo module dependencies' body: | This PR is auto-generated by [create-pull-request][1]. Changes to go.mod: ${{ steps.mod-updates.outputs.MOD_UPDATES }} [1]: https://github.com/peter-evans/create-pull-request labels: dependencies add-paths: | go.mod go.sum **/go.mod **/go.sum ================================================ FILE: .github/workflows/release.yml ================================================ name: Release on: workflow_dispatch: push: branches: - main - beta env: HUSKY: 0 permissions: contents: read # for checkout jobs: release: name: Release runs-on: ubuntu-latest permissions: contents: write # to be able to publish a GitHub release issues: write # to be able to comment on released issues pull-requests: write # to be able to comment on released pull requests id-token: write # to enable use of OIDC for npm provenance steps: - name: Checkout repository uses: actions/checkout@v6 with: fetch-depth: 0 - name: Set up Node.js uses: actions/setup-node@v6 with: node-version: "lts/*" - name: Install dependencies run: npm clean-install - name: Verify the integrity of provenance attestations and registry signatures for installed dependencies run: npm audit signatures - name: Release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: npx semantic-release ================================================ FILE: .gitignore ================================================ _vendor/ prebuild/ prebuild-headers/ prebuild-headers-dev/ prebuild-headers-prod/ public/ resources/ node_modules/ .DS_store .hugo_build.lock # Local Netlify folder and build files .netlify dart-sass/ ================================================ FILE: .gitmodules ================================================ ================================================ FILE: .husky/commit-msg ================================================ npx --no -- commitlint --edit $1 ================================================ FILE: .husky/install.mjs ================================================ // Skip Husky install in production and CI if (process.env.NODE_ENV === 'production' || process.env.CI === 'true') { process.exit(0) } const husky = (await import('husky')).default console.log(husky()) ================================================ FILE: .husky/pre-commit ================================================ npm test ================================================ FILE: .markdownlint-cli2.jsonc ================================================ { "config": { "default": true, "MD013": false, "MD024": false, "MD026": false, "MD034": false, "MD051": false, "MD053": false, "MD055": false, "MD056": false }, "ignores": ["node_modules", "CHANGELOG.md"] } ================================================ FILE: .stylelintignore ================================================ assets/scss/common/_variables.scss assets/scss/components/_syntax-dark.scss assets/scss/components/_syntax-light.scss assets/scss/vendor assets/scss/theme/fonts.scss assets/scss/app-dart.scss assets/scss/app.scss node_modules ================================================ FILE: .stylelintrc.json ================================================ { "extends": "stylelint-config-standard-scss", "rules": { "no-empty-source": null, "scss/comment-no-empty": null, "scss/at-extend-no-missing-placeholder": null, "scss/dollar-variable-colon-space-after": null, "scss/dollar-variable-empty-line-before": null, "color-function-notation": null, "alpha-value-notation": null, "selector-id-pattern": null, "selector-class-pattern": null, "scss/no-global-function-names": null, "color-function-alias-notation": null, "number-max-precision": null, "hue-degree-notation": null, "value-no-vendor-prefix": null, "property-no-vendor-prefix": null, "at-rule-no-unknown": [ true, { "ignoreAtRules": [ "extend", "at-root", "debug", "warn", "error", "if", "else", "for", "each", "while", "mixin", "include", "content", "return", "function", "tailwind", "apply", "responsive", "variants", "screen" ] } ] } } ================================================ FILE: CLAUDE.md ================================================ # CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Overview Hinode is a Hugo theme for documentation and blog sites built on Bootstrap 5. It uses Hugo's module system to manage dependencies. The theme is designed for performance, security (with CSP headers), and SEO. **Version 2 (templatev2 branch)** is a minimal core theme. Optional extensions like mod-blocks add features like pre-built Bookshop components for page building. ## Common Development Commands ### Development Server ```bash npm start # Start Hugo server with module vendoring npm run start:example # Start server using exampleSite npm run start:prod # Start server in production mode npm run start:example:prod # Start exampleSite in production mode ``` ### Building ```bash npm run build # Build site with minification npm run build:example # Build exampleSite npm run build:debug # Build with debug output npm run build:headers # Generate Netlify/server headers ``` ### Linting & Testing ```bash npm test # Run all linters npm run lint # Run all linters npm run lint:scripts # ESLint for JavaScript (assets/js) npm run lint:styles # Stylelint for SCSS npm run lint:markdown # Markdownlint for Markdown files ``` ### Module Management ```bash npm run mod:vendor # Vendor Hugo modules to _vendor/ npm run mod:update # Update all Hugo modules npm run mod:tidy # Clean up unused module dependencies npm run mod:clean # Remove module cache ``` ### Maintenance ```bash npm run clean:public # Remove generated public/ directories npm run clean:install # Remove node_modules and package-lock.json npm run upgrade # Update npm and Hugo module dependencies ``` ## Architecture ### Hugo Module System The theme uses Hugo's module system extensively. All modules are vendored to `_vendor/` for reproducible builds. Key modules include: **Core modules (always loaded):** - `mod-bootstrap` - Bootstrap 5 framework - `mod-utils` - Utility functions and helpers (GetPadding, GetBreakpoint, LogWarn, InitArgs, etc.) - `mod-flexsearch` - Full-text search functionality - `mod-fontawesome` - Icon support **Optional modules:** - `mod-blocks` - Pre-built Bookshop blocks for page building (NOT loaded by default in v2) - `mod-katex`, `mod-mermaid`, `mod-leaflet`, `mod-lottie` - Feature modules Module configuration is in `config/_default/hugo.toml` under `[module.imports]`. Always run `npm run mod:vendor` after module changes. ### Partial Ownership (v2 Architecture) **Hinode owns (core partials):** - `assets/card-group.html`, `assets/nav.html`, `assets/video.html`, `assets/table.html`, `assets/timeline.html` - Used by Hinode shortcodes - `assets/live-image.html`, `assets/live-pages.html` - Used by Hinode templates - `assets/section-title.html` - Section heading utility (used by Hinode pages and mod-blocks components) - All `mod-utils` utilities (GetPadding, GetBreakpoint, LogWarn, InitArgs, etc.) **mod-blocks owns (block-specific partials):** - `assets/hero.html`, `assets/contact.html`, `assets/faq.html`, `assets/menu.html`, `assets/testimonial-carousel.html`, `assets/preview.html` - `utilities/section.html` - Component wrapper - `page/contact.html` - Contact page template **Dependency flow:** ```text Hinode v2 (core theme) ├── mod-utils (GetPadding, LogWarn, etc.) ├── Shared partials (card-group, video, table, section-title, etc.) └── Does NOT import mod-blocks by default mod-blocks v1.1+ (optional extension) ├── 16 Bookshop components ├── Block-specific partials (7 files) └── Depends on Hinode v2 (inherits section-title from Hinode) ``` ### Component Library (Bookshop) - Optional via mod-blocks Bookshop components are provided by the optional **mod-blocks** module. When installed, components live in `component-library/components/`. Each component has: - `*.hugo.html` - Hugo template - `*.scss` - Component styles - `*.bookshop.yml` - Schema definition Components are mounted to multiple locations via `hugo.toml`: - `layouts/partials/bookshop/` - Templates - `data/structures/` - Schemas - `assets/scss/modules/bookshop/` - Styles #### Bookshop Component Architecture Bookshop components follow a two-layer architecture: **1. Component partial** (e.g., `layouts/partials/assets/preview.html`): - Contains the core component logic and rendering - Uses **component-specific arguments** (e.g., `url`, `device`, `heading` for preview) - These arguments should be defined in the component's structure file **2. Bookshop wrapper** (e.g., `component-library/components/preview/preview.hugo.html`): - Calls the component partial with component-specific arguments - Wraps output with `utilities/section.html` for section-level styling - Passes **section arguments** to the wrapper (e.g., `id`, `background`, `width`, `justify`, `wrapper`, `fluid`, `theme`, `cover`, `overlay-mode`, `section-class`, `bg-class`) **Important distinctions:** - **Section arguments are NOT part of the component partial** - they're handled by the section wrapper - **Structure files should only include component-specific arguments** - arguments actively used by the partial - **Section arguments are defined in Bookshop specs** (`.hugo.html` and `.bookshop.yml`) but not in the component's structure file - Example: `preview.yml` defines `url`, `device`, `heading` (used by `preview.html`), but NOT `background`, `width`, etc. (only used by section wrapper) **Example structure:** ```hugo {{/* preview.hugo.html - Bookshop wrapper */}} {{ $raw := partial "assets/preview.html" (dict "url" .url {{/* component-specific */}} "device" .device {{/* component-specific */}} "heading" .heading {{/* component-specific */}} ) }} {{ partial "utilities/section.html" (dict "raw" $raw "background" .background {{/* section argument */}} "width" .width {{/* section argument */}} "theme" .theme {{/* section argument */}} {{/* ... other section arguments ... */}} )}} ``` ### Version 2 Architecture Philosophy **Design Goal:** Hinode v2 is a minimal core theme that works standalone for documentation and blog sites. Optional features are provided through separate modules. **What's in Hinode v2 core:** - Hugo templates for pages, lists, and singles - Shortcode library (accordion, alert, card, carousel, etc.) - Shared partials (section-title, card-group, video, table, timeline) - Bootstrap 5 styling via mod-bootstrap - Search via mod-flexsearch - Icons via mod-fontawesome - Core utilities via mod-utils **What's optional (via modules):** - **mod-blocks** - Pre-built Bookshop components for visual page building - **mod-katex** - LaTeX math rendering - **mod-mermaid** - Diagram rendering - **mod-leaflet** - Interactive maps - **mod-lottie** - Lottie animations **Key architectural decisions:** 1. **No circular dependencies** - Hinode doesn't import mod-blocks; mod-blocks imports Hinode 2. **Clear ownership** - Block-specific partials (hero, contact, faq) live in mod-blocks; shared utilities (section-title, card-group) live in Hinode 3. **Module inheritance** - mod-blocks inherits Hinode's shared partials automatically 4. **Backwards compatibility** - Sites can still use mod-blocks by explicitly importing it ### Directory Structure - `layouts/` - Theme templates and shortcodes - `baseof.html` - Base template with navbar, footer, and content blocks - `_partials/` - Reusable template components - `_shortcodes/` - Hugo shortcodes for content (accordion, alert, card, etc.) - `assets/` - Source assets (JS, SCSS, images, icons) - `scss/` - Organized into components/, layouts/, theme/, helpers/ - `js/` - JavaScript modules - `config/` - Hugo configuration - `_default/hugo.toml` - Main config with module imports - `postcss.config.js` - PostCSS with PurgeCSS and autoprefixer - `content/` - Theme content (minimal, main content in exampleSite) - `data/` - Data files for theme configuration - `i18n/` - Translation files (en, nl, fr, de, pl, pt-br, zh-hans, zh-hant) - `exampleSite/` - Full example site for testing theme - `static/` - Static assets copied directly to output ### CSS Pipeline CSS uses PostCSS with: 1. **Autoprefixer** - Adds vendor prefixes 2. **cssnano** - Minification 3. **PurgeCSS** - Removes unused CSS based on `hugo_stats.json` PurgeCSS safelist is defined in `config/postcss.config.js`. When adding new dynamic classes or Bootstrap components, update the safelist to prevent removal. ### Version Management The theme supports versioned documentation with sidebar menus per version. Version detection happens in `baseof.html` using `utilities/GetVersion.html` partial. ### Shortcodes System Extensive shortcode library in `layouts/_shortcodes/` provides Bootstrap components accessible in Markdown: - Layout: accordion, card, carousel, collapse, navbar, tabs - UI: alert, badge, button, spinner, toast, tooltip - Content: image, video, table, timeline - Typography: abbr, kbd, mark, sub, sup ### Argument and Type Initialization System Hinode uses `mod-utils` to provide a robust argument validation and initialization system for shortcodes, partials, and Bookshop components. **Key components:** - `utilities/InitArgs.html` - Validates and initializes arguments with type checking and defaults - `utilities/InitTypes.html` - Loads type definitions and merges structure-specific with global definitions - `data/structures/_arguments.yml` - Global argument definitions (type, default, options, etc.) - `data/structures/.yml` - Structure-specific argument definitions for each shortcode or component **How it works:** 1. **Structure definition inheritance:** Each shortcode/component has a structure file (e.g., `example.yml`) that defines its arguments. These definitions automatically inherit from the global `_arguments.yml` file. 2. **Automatic camelCase conversion:** Hyphenated argument names (e.g., `show-preview`) are automatically converted to camelCase (e.g., `showPreview`) for easier access in templates. Both versions are available: `$args.show-preview` and `$args.showPreview`. 3. **Default value application:** Arguments with `default` or `config` fields in their definition are automatically initialized with those values if not provided by the user. 4. **Type validation:** Arguments are validated against their declared types. The system automatically casts between compatible types (e.g., string `"true"` to boolean `true`). 5. **Deprecation warnings:** Deprecated arguments (marked with `deprecated` field) trigger warnings when used, guiding users to the preferred alternative. **Structure definition format:** Structure files follow the DRY principle with clear separation of concerns: **Global definitions** (`mod-utils/data/structures/_arguments.yml`): - `type` - Argument data type - `default` - Default value (if applicable) - `options` - Valid values for select types - `comment` - Description of what the argument does **Component-specific definitions** (`data/structures/.yml`): - `optional` - Whether argument is required or optional - `deprecated` - Version when argument was deprecated (component-specific) - `alternative` - Replacement argument when deprecated (component-specific) - `release` - Version when argument was introduced (component-specific) ```yaml # Component structure file (e.g., data/structures/preview.yml) comment: >- Renders a live URL preview with switchable device views. arguments: url: optional: false release: v1.0.0 device: optional: true release: v1.0.0 heading: optional: true release: v1.0.0 old-param: optional: true deprecated: v1.1.0 alternative: device ``` ```yaml # Global argument definitions (mod-utils/data/structures/_arguments.yml) arguments: url: type: string comment: >- Address of the link destination, either a local reference or an external address. Include the `scheme` when referencing an external address. device: type: select default: desktop comment: >- Device view to display by default in preview component. Determines the initial iframe dimensions and active tab. options: values: - desktop - tablet - mobile heading: type: heading comment: >- Heading of the content block, including a preheading and content element. ``` **When to add to _arguments.yml:** - New argument used by multiple components - add full type definition to global file - Component-specific argument - can define inline in structure file (but prefer global for reusability) - Override default or add options - define inline in structure file (inherits base type from global) **Common pitfall - Boolean argument handling:** When accessing boolean arguments that could be explicitly set to `false`, **DO NOT use the `or` operator** for fallback logic: ```hugo {{/* WRONG - or operator treats false as falsy and skips it */}} {{- $showPreview := or $args.showPreview $args.show_preview }} {{/* CORRECT - directly access the camelCase version */}} {{- $showPreview := $args.showPreview }} ``` The `or` operator returns the first truthy value, so `or false ` will skip `false` and return the fallback instead of honoring the explicit `false` value. **Best practices:** - Always use `InitArgs` at the start of shortcodes and partials to validate arguments - Define structure files in `data/structures/` for all shortcodes and components - **Structure files should only reference arguments by name** - type definitions go in `_arguments.yml` - **Only include arguments actively used by the component partial** - section arguments (like `id`, `background`, `width`, `justify`, `wrapper`, `fluid`, `theme`, `cover`, `overlay-mode`, `section-class`, `bg-class`) are handled by the Bookshop section wrapper and should NOT be in the component's structure file - Add new argument types to `mod-utils/data/structures/_arguments.yml` for reuse across components - Mark `deprecated`, `alternative`, and `release` in **component structure files** (component-specific metadata) - Use hyphenated names for new arguments (e.g., `show-preview` not `show_preview`) - Access arguments via their camelCase versions (e.g., `$args.showPreview`) **Example usage in a shortcode:** ```hugo {{/* Initialize and validate arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "example" "args" .Params "named" .IsNamedParams "group" "shortcode" ) -}} {{/* Check for errors/warnings */}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/example.html" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{- end -}} {{/* Access arguments using camelCase */}} {{- $showPreview := $args.showPreview }} {{- $showMarkup := $args.showMarkup }} ``` ### Content Security Policy CSP headers are auto-generated via Hugo's segments feature. The theme includes `mod-csp` for Content Security Policy management. Headers are defined in `netlify.toml` and generated via `npm run build:headers`. ### Internationalization Multi-language support with translations in `i18n/`. Default language is English (`en-us`). Language configuration in `config/_default/hugo.toml`. ### Page Templates (v2) **List pages** (`layouts/list.html`): - If page has `content_blocks` frontmatter → renders via `page/blocks.html` (requires mod-blocks) - Otherwise → renders via `page/articles.html` (core Hinode, uses section-title.html for header) **Single pages** (`layouts/single.html`): - Renders content via `utilities/ProcessContent` partial - If page has `content_blocks` → also renders via `page/blocks.html` **Key partials:** - `page/articles.html` - Default list page rendering with section-title header and card grid - `page/blocks.html` - Renders Bookshop content blocks (requires mod-blocks) - `assets/section-title.html` - Shared heading utility with preheading, subtitle, links support ## Key Configuration Files - `hugo.toml` - Main Hugo config with modules, mounts, build settings - `package.json` - npm scripts and dependencies - `go.mod` - Hugo module dependencies (Go modules) - `postcss.config.js` - PostCSS pipeline with PurgeCSS safelist - `netlify.toml` - Netlify build config and security headers - `.eslintrc.yml` - JavaScript linting (ES6, browser environment) - `.stylelintrc.json` - SCSS linting (standard-scss) - `.markdownlint-cli2.jsonc` - Markdown linting rules ## Important Development Notes ### When Working with mod-blocks (Optional) **Note:** Hinode v2 does NOT include mod-blocks by default. If you need Bookshop components: 1. Add mod-blocks to `hugo.toml`: `path = "github.com/gethinode/mod-blocks"` 2. Run `npm run mod:vendor` to vendor the module 3. Components live in mod-blocks repository at `component-library/components/` 4. Each component has three files: `.hugo.html`, `.scss`, `.bookshop.yml` 5. Update PurgeCSS safelist in `config/postcss.config.js` if components add dynamic classes ### When Adding Hugo Modules 1. Add to `go.mod` requires section 2. Add to `[module.imports]` in `hugo.toml` 3. Run `npm run mod:vendor` to vendor the module 4. If module has styles, add to PurgeCSS safelist in `postcss.config.js` ### When Working with Layouts - `baseof.html` is the main template; it sets up version-aware menus, content blocks, overlay mode - Partials in `_partials/` are organized: `head/`, `footer/`, `page/`, `utilities/`, `assets/` - The theme uses `.Scratch` extensively for passing data between partials ### Build Process 1. `hugo mod vendor` - Vendors modules to `_vendor/` 2. Hugo build generates `hugo_stats.json` with used classes/tags/ids 3. PostCSS processes SCSS, using `hugo_stats.json` to purge unused CSS 4. Final output in `public/` or `exampleSite/public/` ### Testing Changes Test with both main site and exampleSite: - `npm start` - Test theme directly - `npm run start:example` - Test with full example content - `npm run lint` - Check code quality before committing ### Git Workflow - Main branch: `main` (production releases) - Development branch: `develop` - Uses semantic-release for automated versioning - Commits follow Angular Conventional Commits (enforced by commitlint) - Husky pre-commit hooks run linters automatically ### Commit Message Format Follow Angular Conventional Commits format: ```text (): 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 ``` **Common types:** - `feat` - New feature - `fix` - Bug fix - `refactor` - Code refactoring - `style` - Styling changes (CSS/SCSS only, no logic changes) - `docs` - Documentation changes - `test` - Adding or updating tests - `chore` - Build process, dependencies, tooling **Common scopes:** - `i18n` - Internationalization/translations - `components` - Component changes - `docs` - Documentation - `theme` - Theme styling - `build` - Build process **Example commits:** - `feat(i18n): add missing translations for testimonials` - `fix(components): correct variable reference in testimonials` - `style: add width constraint to section-title class` - `refactor(components): improve testimonials component layout` ### Linting & Code Quality Run linters before committing (pre-commit hooks will enforce this): ```bash npm test # Run all linters (recommended before commits) npm run lint:scripts # Check JavaScript npm run lint:styles # Check SCSS npm run lint:markdown # Check Markdown documentation ``` **Linting tools:** - **ESLint** (`.eslintrc.yml`) - JavaScript linting with ES6 and browser environment - **Stylelint** (`.stylelintrc.json`) - SCSS linting with standard-scss rules - **Markdownlint** (`.markdownlint-cli2.jsonc`) - Markdown file linting **Markdown linting rules** (`.markdownlint-cli2.jsonc`): - Enforced: MD040 (fenced code blocks must have language specified), MD032 (lists must be surrounded by blank lines), and others - Disabled rules: MD013 (line length), MD024 (duplicate headers), MD026 (trailing punctuation), MD034 (bare URLs), MD051 (link fragments), MD053 (link reference definitions), MD055 (table pipe escaping), MD056 (table header/body cell count) - Ignored: `node_modules/`, `CHANGELOG.md` **Commit message linting** (enforced by commitlint via pre-commit hooks): - Body lines must not exceed 100 characters (enforced by `body-max-line-length`) - When formatting multi-line bullet points, break long lines at 100 characters - Use indentation (2 spaces) for continuation lines to maintain readability Example of correctly formatted commit message: ```text refactor: consolidate version detection into modular partials - Replace theme-version.html with improved version.html partial - Extract version detection logic into reusable modular partials (mod-version and env-version) - Update version regex to support both major version (v2) and non-versioned module paths - Add fallback to HUGO_HINODE_VERSION environment variable for CI/CD builds ``` **Important notes:** - Pre-commit hooks run automatically when committing - If hooks modify files (e.g., formatting), the commit will fail and you should commit again - Always test changes with the example site: `npm run build:example` - Check for i18n warnings when modifying translations - Ensure all language variants build without warnings - If using mod-blocks, test that components still work after Hinode changes ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2022 - 2026 Hinode Team / Mark Dumay 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 ================================================ # Hugo Theme Hinode

A clean documentation and blog theme for your Hugo site based on Bootstrap 5

Hugo website Hinode theme Netlify Status UptimeRobot Status Last commit Issues Pulls License

AboutPrerequisitesInstallationConfigurationContributingDonateLicense

## About ![Logo](https://raw.githubusercontent.com/gethinode/hinode/main/static/img/logo.png) - [Online Demo][demo] - [PageSpeed Insights][pagespeed] - [Mozilla Observatory][observatory] Hinode is a clean documentation and blog theme for [Hugo][hugo], an open-source static site generator. Based on the [Bootstrap 5][bootstrap] framework, the rendered site is fast, secure, and responsive. Hinode uses [FlexSearch][flexsearch] to enable full text search across your site. Finally, the theme supports [Node Package Manager][npm] (npm) to automate the build process and to keep track of dependencies. Detailed information about Hinode is available on the [official website][website]. ## Prerequisites Hinode is a [Hugo theme that uses modules][hugo_modules] to install and maintain various components. It can be installed using either Hugo or npm. If you would like to take advantage of automation, the npm approach is recommended. Refer to the [Hinode template][repository_template] for installation instructions with npm. The installation instructions in this readme install Hinode as a regular Hugo theme. Hinode requires the following software to be installed on your local machine. - [Go binary][golang_download] - [Hugo][hugo_download] (extended version) [Git][git_download] is recommended, but is not a strict requirement. ## Installation
Installation notes for Windows The installation for Windows requires PowerShell v7. Download it from the Microsoft Store as needed. Check your current version with the command `$PSVersionTable`.
Start a new Hinode project in three steps: 1. **Create a new site** ```bash hugo new site my-hinode-site && cd my-hinode-site ``` 2. **Initialize the module system** ```bash hugo mod init example.com/my-hinode-site echo "[[module.imports]]" >> hugo.toml echo "path = 'github.com/gethinode/hinode'" >> hugo.toml ``` 3. **Start a development server** ```bash hugo server ``` ## Optional Extensions Hinode v2 is a minimal core theme. Optional extensions are available to add features: - **[mod-blocks][mod-blocks]** - Pre-built Bookshop blocks for quickly building page layouts (hero, cards, FAQ, testimonials, etc.) - Other modules - See the [official modules list][modules] To add mod-blocks to your site: ```toml [[module.imports]] path = "github.com/gethinode/mod-blocks" ``` ## Configuration See the [official documentation][getstarted] on how to configure your site. ## Contributing See the [official documentation][contribute] on how to contribute to the open-source development of Hinode. ## Credits Hinode is inspired by the following themes: - [Blist][blist] - a clean and fast blog theme for your Hugo site using Tailwind CSS. - [Doks][doks] - a Hugo theme for building secure, fast, and SEO-ready documentation websites, which you can easily update and customize. ## Donate Buy Me A Coffee ## License The `hinode`, `docs`, and `template` codebase is released under the [MIT license][license]. The documentation of Hinode is licensed under the Creative Commons [(CC BY-NC 4.0)][cc-by-nc-4.0] license. This includes all files within the repository's `/content` and `/exampleSite/content` folders and their children, as well as the "README" in the repository root. This applies to all public repositories maintained by `gethinode` on GitHub, including the `gethinode/hinode`, `gethinode/template`, and `gethinode/docs` repositories, unless specified otherwise. [blist]: https://github.com/apvarun/blist-hugo-theme [bootstrap]: https://getbootstrap.com [cc-by-nc-4.0]: https://creativecommons.org/licenses/by-nc/4.0/ [doks]: https://github.com/h-enk/doks [flexsearch]: https://github.com/nextapps-de/flexsearch [git_download]: https://git-scm.com [hugo]: https://gohugo.io [hugo_download]: https://gohugo.io/installation [hugo_modules]: https://gohugo.io/hugo-modules/ [netlify]: https://www.netlify.com [nodejs]: https://nodejs.org [npm]: https://www.npmjs.com [observatory]: https://observatory.mozilla.org/analyze/demo.gethinode.com [pagespeed]: https://pagespeed.web.dev/report?url=https%3A%2F%2Fdemo.gethinode.com%2F [contribute]: https://gethinode.com/contribute [getstarted]: https://gethinode.com/docs [golang_download]: https://go.dev/dl/ [mod-blocks]: https://github.com/gethinode/mod-blocks [modules]: https://gethinode.com/docs/getting-started/modules/ [demo]: https://demo.gethinode.com/ [license]: https://github.com/gethinode/hinode/blob/main/LICENSE [repository]: https://github.com/gethinode/hinode.git [repository_template]: https://github.com/gethinode/template.git [website]: https://gethinode.com/ ================================================ FILE: archetypes/default.md ================================================ --- # author: title: {{ replace .Name "-" " " | title }} date: {{ .Date }} draft: true # layout: # description: # tags: # icon: # thumbnail: # url: # author: # authorURL: # origin: # originURL: --- ================================================ FILE: assets/js/alert.js ================================================ /* eslint-disable no-undef */ const alert = document.getElementById('page-alert') const closeBtn = document.getElementById('page-alert-btn-close') if (alert !== null && closeBtn !== null) { const version = alert.getAttribute('data-page-alert-version') || 'unknown' const hideAlert = getSessionStorage(`page-alert-${version}`, null, 'functional') !== null if (hideAlert) { alert.classList.add('d-none') } closeBtn.addEventListener('click', () => { setSessionStorage(`page-alert-${version}`, 'seen', 'functional') alert.classList.add('d-none') }) } ================================================ FILE: assets/js/animation.js ================================================ function reveal () { const reveals = document.querySelectorAll('.reveal') for (let i = 0; i < reveals.length; i++) { const windowHeight = window.innerHeight const elementTop = reveals[i].getBoundingClientRect().top const elementVisible = 150 if (elementTop < windowHeight - elementVisible) { reveals[i].classList.add('active') reveals[i].classList.remove('reveal') } else { reveals[i].classList.remove('active') } } } window.addEventListener('scroll', reveal) ================================================ FILE: assets/js/clipboard.js ================================================ /* Source: - https://simplernerd.com/hugo-add-copy-to-clipboard-button/ */ const svgCopy = '' const svgCheck = '' const addCopyButtons = clipboard => { // 1. Look for pre > code elements in the DOM document.querySelectorAll('pre > code').forEach(codeBlock => { // 2. Create a button that will trigger a copy operation const button = document.createElement('button') button.className = 'clipboard-button' button.setAttribute('data-toast-target', 'toast-copied-code-message') button.setAttribute('aria-label', '{{ T "copyToClipboard" }}') button.type = 'button' button.innerHTML = svgCopy button.addEventListener('click', () => { const text = codeBlock.innerText.split('\n').filter(Boolean).join('\n') clipboard.writeText(text).then( () => { button.blur() button.innerHTML = svgCheck setTimeout(() => (button.innerHTML = svgCopy), 2000) }, () => (button.innerHTML = 'Error') ) }) // 3. Append the button directly before the pre tag const pre = codeBlock.parentNode pre.parentNode.insertBefore(button, pre) }) } if (navigator && navigator.clipboard) { addCopyButtons(navigator.clipboard) } document.querySelectorAll('[data-clipboard]').forEach(trigger => { const text = trigger.getAttribute('data-clipboard') trigger.addEventListener('click', () => { navigator.clipboard.writeText(text) }) }) ================================================ FILE: assets/js/critical/_cookie.js ================================================ /* eslint-disable no-unused-vars */ function hasConsent (category) { // TODO: placeholder function return true } function getLocalStorage (key, def, category) { if (hasConsent(category)) { return localStorage.getItem(key) } else { return def } } function setLocalStorage (key, val, category) { if (hasConsent(category)) { localStorage.setItem(key, val) } } function getSessionStorage (key, def, category) { if (hasConsent(category)) { return sessionStorage.getItem(key) } else { return def } } function setSessionStorage (key, val, category) { if (hasConsent(category)) { sessionStorage.setItem(key, val) } } ================================================ FILE: assets/js/critical/color.js ================================================ {{- if (or site.Params.main.enableDarkMode site.Params.main.colorMode.enabled) -}} /*! * Color mode toggler for Bootstrap's docs (https://getbootstrap.com/) * Copyright 2011-2022 The Bootstrap Authors * Licensed under the Creative Commons Attribution 3.0 Unported License. */ (() => { 'use strict' const supportedThemes = ['auto', 'dark', 'light']; // retrieves the currently stored theme from local storage const storedTheme = getLocalStorage('theme', 'auto', 'functional') // retrieves the theme preferred by the client, defaults to light function getPreferredTheme() { return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' } // retrieves the current theme, either from local storage or client's preferences function getTheme() { if (storedTheme) { return storedTheme } else { const preference = getPreferredTheme() setLocalStorage('theme', preference, 'functional') return preference } } // applies and stores requested theme function setTheme(theme) { if (!supportedThemes.includes(theme)) { theme = 'auto' } setLocalStorage('theme', theme, 'functional') if (theme === 'auto') { theme = getPreferredTheme() } document.documentElement.setAttribute('data-bs-theme', theme) // store main theme separately, to avoid the navbar mode icon uses a local variable document.documentElement.setAttribute('data-bs-main-theme', theme) updateSelectors() } // alternates the currently active theme function toggleTheme() { const target = document.documentElement.getAttribute('data-bs-theme') === 'dark' ? 'light' : 'dark' setTheme(target) } function updateSelectors() { document.querySelectorAll('.navbar-mode-selector').forEach(chk => { chk.checked = (document.documentElement.getAttribute('data-bs-theme') === 'light') }) } window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { if (storedTheme !== 'light' || storedTheme !== 'dark') { setTheme(getPreferredTheme()) } }) window.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('.navbar-mode-selector').forEach(chk => { chk.addEventListener('change', function () { document.documentElement.setAttribute('data-bs-theme-animate', 'true') toggleTheme() }) }) }) window.addEventListener('load', () => { // update the selectors when all elements are ready updateSelectors() }) // initialize theme as soon as possible to reduce screen flickering setTheme(getTheme()) })() {{- end -}} ================================================ FILE: assets/js/critical/languageSelector.js ================================================ /* eslint-disable */ {{- if site.Params.main.enableLanguageSelectionStorage -}} {{- $folder := (urls.Parse site.BaseURL).Path | default "/" -}} (() => { 'use strict' const folder = '{{ $folder }}' // Function to get the selected language from local storage function getLanguage () { return getLocalStorage('selectedLanguage', document.documentElement.lang, 'functional') } // Function to set the selected language in local storage function setLanguage (language) { setLocalStorage('selectedLanguage', language, 'functional') } // Function to apply the selected language to the website function applyLanguage (language, href) { if (document.documentElement.lang !== language) { if (href) { if (window.location.pathname !== href) { window.location.href = href } } else { let target = folder + language + '/' if (window.location.href !== target) { window.location.href = target } } } } // Event listener for language selection document.addEventListener('DOMContentLoaded', () => { // override stored language when query string contains force is true let params = new URLSearchParams(document.location.search) let force = params.get('force') if (force !== null && force.toLowerCase() == 'true') { setLanguage(document.documentElement.lang) return } // continue with regular code const storedLanguage = getLanguage() const languageItems = document.querySelectorAll('#language-selector[data-translated=true] .dropdown-item') const link = document.querySelector("link[rel='canonical']") let alias = '' if (link !== null) { alias = link.getAttribute('href') } if ((alias !== '') && (window.location.href !== alias)) { window.location.href = alias } else if (languageItems.length > 0) { // Redirect if the stored language differs from the active language if ((storedLanguage) && (document.documentElement.lang !== storedLanguage)) { languageItems.forEach(item => { if (item.getAttribute('hreflang') === storedLanguage) { applyLanguage(storedLanguage, item.getAttribute('href')) } }) } // Update the stored language when the user selects a new one languageItems.forEach(item => { item.addEventListener('click', () => { const selectedLanguage = item.getAttribute('hreflang') if (selectedLanguage) { setLanguage(selectedLanguage) } }) }) } else { // overrule the current stored language when no translation is available setLanguage(document.documentElement.lang) } }) })() {{- end -}} /* eslint-enable */ ================================================ FILE: assets/js/critical/sidebar-pre-init.js ================================================ // Pre-apply sidebar collapsed state before body renders to prevent label flash. (function () { try { if (localStorage.getItem('sidebar-collapsed') === '1') { document.documentElement.classList.add('sidebar-pre-collapsed') } } catch { /* ignore localStorage errors */ } }()) ================================================ FILE: assets/js/menu.js ================================================ const url = new URL(window.location.href) const menu = url.searchParams.get('menu') const child = url.searchParams.get('child') const menuItems = document.querySelectorAll('[data-nav="main"]') if (menu !== null) { menuItems.forEach(element => { element.classList.remove('active') }) const targetMainItems = document.querySelectorAll(`[data-nav-main="${menu}"]:not([data-nav-child])`) targetMainItems.forEach(element => { element.classList.add('active') }) const targetChildItems = document.querySelectorAll(`[data-nav-main="${menu}"][data-nav-child="${child}"]`) targetChildItems.forEach(element => { element.classList.add('active') }) } ================================================ FILE: assets/js/modal.js ================================================ document.addEventListener('hide.bs.modal', function (_event) { // Remove the focus from the active element if (document.activeElement) { document.activeElement.blur() } }) ================================================ FILE: assets/js/nav.js ================================================ function updateDropdown (element, id, label) { const dropdown = document.getElementById(element) if (dropdown != null) { dropdown.querySelector('.dropdown-toggle').textContent = label dropdown.querySelectorAll('.panel-dropdown .dropdown-item').forEach(item => { item.classList.remove('active') let target = item.getAttribute('data-link') if (target != null) { target = target.replace(/^#+/, '') if (target === id) { item.classList.add('active') } } }) } } document.querySelectorAll('.panel-dropdown').forEach(trigger => { trigger.addEventListener('hide.bs.dropdown', event => { if (event.clickEvent != null) { let target = event.clickEvent.srcElement.getAttribute('data-link') if (target != null) { trigger.querySelectorAll('.panel-dropdown .dropdown-item').forEach(item => { item.classList.remove('active') }) target = target.replace(/^#+/, '') const btn = document.getElementById(target) if (btn != null) { event.clickEvent.srcElement.classList.add('active') trigger.querySelector('.dropdown-toggle').textContent = event.clickEvent.srcElement.textContent btn.click() } } } }) }) document.querySelectorAll('.nav-panel .nav-link').forEach(trigger => { trigger.addEventListener('click', event => { const companion = event.srcElement.parentElement.parentElement.getAttribute('data-companion') if (companion != null) { updateDropdown(companion, trigger.getAttribute('id'), trigger.textContent.trim()) } }) }) ================================================ FILE: assets/js/navbar.js ================================================ const fixed = {{ site.Params.navigation.fixed }} const navbar = document.querySelector('.navbar') const togglers = document.querySelectorAll('.main-nav-toggler') const modeSelectors = document.querySelectorAll('.switch-mode-collapsed') const colorsBG = ['body', 'secondary', 'tertiary'] let scrollPosition = 0 function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)) } function getStyle(el, styleProp) { let y if (window.getComputedStyle) { y = document.defaultView.getComputedStyle(el).getPropertyValue(styleProp) } else if (el.currentStyle) { y = el.currentStyle[styleProp] } return y } function updateNavbarColor () { const scrollTop = window.pageYOffset const scrollBottom = scrollTop + navbar.offsetHeight // find which section is currently under the navbar let currentSection = null const sections = document.querySelectorAll('article,section,footer') let currentIndex = -1 sections.forEach(section => { const rect = section.getBoundingClientRect() const sectionTop = scrollTop + rect.top const sectionBottom = sectionTop + section.offsetHeight - 1 // check if navbar overlaps with this section if (scrollTop <= sectionBottom && scrollBottom >= sectionTop) { let index = getStyle(section, 'z-index') if (index === 'auto') { index = 1 } if (index > currentIndex) { currentSection = section currentIndex = index } } }) // use main part as backup (defined in baseof.html template) if (!currentSection) { currentSection = document.querySelector('main') } if (currentSection) { adaptToSection(currentSection) } } function getBackgroundColor (section) { // get computed background color of the section let color = window.getComputedStyle(section).backgroundColor // use body background when section background is undefined or transparent if (color === 'rgba(0, 0, 0, 0)' || color === 'transparent') { color = window.getComputedStyle(document.body).getPropertyValue('background-color') } return color } function adaptToSection (section) { // retrieve the section background color, using body color as fallback const color = getBackgroundColor(section) // determine if the background is light or dark const isLightBackground = isLightColor(section, color) // set appropriate mode class const nav = document.querySelector('.navbar') if (isLightBackground) { if (navbar.dataset.bsTheme !== 'light') { navbar.dataset.bsTheme = 'light' } } else { if (navbar.dataset.bsTheme !== 'dark') { navbar.dataset.bsTheme = 'dark' } } // update semi-transparent background color of navbar const rgb = parseRGB(color) if (rgb) { navbar.style.backgroundColor = `rgba(${rgb.r},${rgb.g},${rgb.b},.4)` } } function isLightColor (section, color) { if (section.dataset.bsTheme === 'light') { return true } if (section.dataset.bsTheme === 'dark') { return false } // parse RGB color of the section backgroiund const rgb = parseRGB(color) if (!rgb) return true // Default to light if can't parse // calculate relative luminance const luminance = calculateLuminance(rgb.r, rgb.g, rgb.b) // return true if light (luminance > 0.5) return luminance > 0.5 } function parseRGB (color) { const match = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/) if (match) { return { r: parseInt(match[1]), g: parseInt(match[2]), b: parseInt(match[3]) } } return null } function calculateLuminance (r, g, b) { // convert RGB to relative luminance using sRGB formula const [rs, gs, bs] = [r, g, b].map(c => { c = c / 255 return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4) }) return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs } function updateNavbar () { if (navbar.dataset.transparent) { if (window.scrollY > 0) { navbar.classList.add('navbar-scrolled') } else { navbar.classList.remove('navbar-scrolled') } updateNavbarColor() if (window.scrollY === 0) { navbar.style.backgroundColor = '' } } else { let storedTheme if (typeof getLocalStorage === "function") { storedTheme = getLocalStorage('theme', null, 'functional') } if (window.scrollY > 75) { navbar.classList.add('nav-active') if (storedTheme) { navbar.setAttribute('data-bs-theme', storedTheme) } } else { navbar.classList.remove('nav-active') const defaultTheme = navbar.getAttribute('data-bs-overlay') const targetTheme = defaultTheme ? defaultTheme : storedTheme if (targetTheme) { navbar.setAttribute('data-bs-theme', defaultTheme) } } } } if ((navbar !== null) && (window.performance.getEntriesByType)) { if (window.performance.getEntriesByType('navigation')[0].type === 'reload') { fixed && updateNavbar() } } if (navbar !== null && togglers !== null) { // initialize and update the navbar on load, on resize, and on scroll document.addEventListener('DOMContentLoaded', () => { fixed && updateNavbar() }) window.addEventListener('resize', () => { fixed && updateNavbar() for (let i = 0; i < togglers.length; ++i) { const toggler = togglers[i] if (toggler.getAttribute('aria-expanded') === 'true') { toggler.click() } } }) document.addEventListener('scroll', () => fixed && updateNavbar()) // hook up collapse events document.querySelectorAll('.navbar-collapse').forEach((collapse) => { collapse.addEventListener('show.bs.collapse', function () { scrollPosition = window.pageYOffset document.body.style.top = `-${scrollPosition}px` document.body.classList.add('navbar-open') }) collapse.addEventListener('hide.bs.collapse', function () { document.body.classList.remove('navbar-open') document.body.style.top = '' window.scrollTo({ top: scrollPosition, behavior: 'instant' }) }) }) // observe state changes to the site's color mode const html = document.querySelector('html') const config = { attributes: true, attributeFilter: ['data-bs-theme'] } const Observer = new MutationObserver(() => { if (fixed) { // wait for the theme animation to finish sleep(600).then(() => { updateNavbar() }) } }) Observer.observe(html, config) // initialize background color if (!navbar.dataset.transparent) { const color = (navbar.getAttribute('data-navbar-color') || 'body') const bg = colorsBG.includes(color) ? `var(--bs-${color}-bg)` : `var(--bs-navbar-color-${color})` navbar.style.setProperty('--bs-navbar-expanded-color', bg) } // update the navbar background color when expanded for (let i = 0; i < togglers.length; ++i) { togglers[i].onclick = () => { navbar.classList.toggle('navbar-expanded') } } // invoke the navbar toggler for each mode switcher to collapse the main menu afterwards for (let i = 0; i < modeSelectors.length; ++i) { modeSelectors[i].onclick = () => { for (let j = 0; j < togglers.length; ++j) { const toggler = togglers[j] if (toggler.getAttribute('aria-expanded') === 'true') { toggler.click() } } } } } ================================================ FILE: assets/js/optional/.gitkeep ================================================ ================================================ FILE: assets/js/popover.js ================================================ const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="popover"]') // eslint-disable-next-line no-undef, no-unused-vars const popoverList = [...popoverTriggerList].map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl)) ================================================ FILE: assets/js/sharing.js ================================================ {{- if site.Params.sharing.webshare -}} // Adapted from: https://dev.to/j471n/how-to-share-anything-from-your-website-by-web-share-api-1h5g // function for Web Share API function webShareAPI (title, description, link) { navigator .share({ title, text: description, url: link }) .then(() => console.log('Successful share')) .catch((error) => console.log('Error sharing', error)) } const shareButtons = document.querySelectorAll('[data-sharing-url]') shareButtons.forEach(btn => { if (navigator.share) { const title = btn.getAttribute('data-sharing-title') const description = btn.getAttribute('data-sharing-description') const url = btn.getAttribute('data-sharing-url') // show button if it supports webShareAPI btn.style.display = 'block' btn.addEventListener('click', () => webShareAPI(title, description, url) ) } else { // hide button if host does not support Web Share API btn.style.display = 'none' } }) {{- end -}} ================================================ FILE: assets/js/sidebar-group.js ================================================ (function () { 'use strict' var STORAGE_KEY = 'sidebar-secondary-collapsed' function init () { var nav = document.querySelector('.sidebar-collapsible') if (!nav) return var btn = nav.querySelector('[data-bs-toggle="collapse"][data-bs-target^="#sidebar-secondary-"]') if (!btn) return var target = document.querySelector(btn.getAttribute('data-bs-target')) if (!target) return // Restore persisted state — default is collapsed (stored = true) var stored = true try { var v = localStorage.getItem(STORAGE_KEY) if (v !== null) stored = v === '1' } catch { /* ignore localStorage errors */ } if (!stored) { target.classList.add('show') btn.setAttribute('aria-expanded', 'true') } target.addEventListener('show.bs.collapse', function () { btn.setAttribute('aria-expanded', 'true') try { localStorage.setItem(STORAGE_KEY, '0') } catch { /* ignore localStorage errors */ } }) target.addEventListener('hide.bs.collapse', function () { btn.setAttribute('aria-expanded', 'false') try { localStorage.setItem(STORAGE_KEY, '1') } catch { /* ignore localStorage errors */ } }) } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init) } else { init() } }()) ================================================ FILE: assets/js/sidebar-toggle.js ================================================ (function () { 'use strict' function setCollapsed (nav, collapsed) { var storageKey = nav.getAttribute('data-storage-key') || 'sidebar-collapsed' nav.classList.toggle('sidebar-collapsed', collapsed) var btn = nav.querySelector('.sidebar-toggle-btn') if (btn) btn.setAttribute('aria-expanded', String(!collapsed)) if (typeof bootstrap !== 'undefined') { var items = nav.querySelectorAll('[data-sidebar-label]') if (collapsed) { items.forEach(function (el) { el.setAttribute('data-bs-toggle', 'tooltip') el.setAttribute('data-bs-placement', 'right') el.setAttribute('title', el.getAttribute('data-sidebar-label')) if (!bootstrap.Tooltip.getInstance(el)) { new bootstrap.Tooltip(el) } }) } else { items.forEach(function (el) { var tt = bootstrap.Tooltip.getInstance(el) if (tt) tt.dispose() el.removeAttribute('data-bs-toggle') el.removeAttribute('data-bs-placement') el.removeAttribute('title') }) } } try { localStorage.setItem(storageKey, collapsed ? '1' : '0') } catch { /* ignore localStorage errors */ } nav.dispatchEvent(new CustomEvent('hinode:sidebar-toggle', { bubbles: true, detail: { collapsed: collapsed } })) } function init () { var nav = document.querySelector('.sidebar-collapsible') if (!nav) return var btn = nav.querySelector('.sidebar-toggle-btn') if (!btn) return var storageKey = nav.getAttribute('data-storage-key') || 'sidebar-collapsed' var stored = false try { stored = localStorage.getItem(storageKey) === '1' } catch { /* ignore localStorage errors */ } nav.classList.add('sidebar-no-transition') setCollapsed(nav, stored) document.documentElement.classList.remove('sidebar-pre-collapsed') nav.offsetHeight // force reflow before re-enabling transitions nav.classList.remove('sidebar-no-transition') btn.addEventListener('click', function () { setCollapsed(nav, !nav.classList.contains('sidebar-collapsed')) }) } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init) } else { init() } }()) ================================================ FILE: assets/js/testimonial.js ================================================ function adjustCarouselHeight () { let max = 0 document.querySelectorAll('.testimonials .carousel-item').forEach(container => { const clone = container.cloneNode(true) clone.style.display = 'block' clone.style.visibility = 'hidden' clone.style.height = 'auto' container.parentNode.appendChild(clone) if (clone.offsetHeight > max) max = clone.offsetHeight container.parentNode.removeChild(clone) }) document.querySelectorAll('.testimonials .carousel-item').forEach(container => { container.style.height = max + 'px' }) } window.addEventListener('load', () => { adjustCarouselHeight() }) window.addEventListener('resize', () => { adjustCarouselHeight() }) ================================================ FILE: assets/js/toast.js ================================================ // Script to move all embedded toast messages into a container with id 'toast-container'. The container ensures multiple // toast messages are stacked properly. The script targets all elements specified by a 'data-toast-target' and ensures // the click event of the origin is linked as well. const container = document.getElementById('toast-container') if (container !== null) { // process all data-toast-target elements document.querySelectorAll('[data-toast-target]').forEach(trigger => { const target = document.getElementById(trigger.getAttribute('data-toast-target')) if (target !== null) { // move the element to the toast containr container.appendChild(target) // eslint-disable-next-line no-undef const toast = bootstrap.Toast.getOrCreateInstance(target) if (toast !== null) { // associate the click event of the origin with the toast element trigger.addEventListener('click', () => { toast.show() }) } } }) } ================================================ FILE: assets/js/toc.js ================================================ const btnTOCShowMore = document.getElementById('btnTOCShowMore') if (btnTOCShowMore !== null) { btnTOCShowMore.addEventListener('click', _e => { btnTOCShowMore.style.display = 'none' }) } const btnTOCShowLess = document.getElementById('btnTOCShowLess') if ((btnTOCShowLess !== null) && (btnTOCShowMore !== null)) { btnTOCShowLess.addEventListener('click', _e => { btnTOCShowMore.style.display = 'initial' }) } ================================================ FILE: assets/js/tooltip.js ================================================ // Bootstrap tooltip example: https://getbootstrap.com/docs/5.2/components/tooltips/ const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]') // eslint-disable-next-line no-unused-vars, no-undef const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl)) ================================================ FILE: assets/js/vendor/.gitkeep ================================================ ================================================ FILE: assets/js/video.js ================================================ document.querySelectorAll('[data-video-padding]').forEach(element => { element.style.paddingBottom = element.getAttribute('data-video-padding') }) ================================================ FILE: assets/scss/app-dart.scss ================================================ @use "sass:meta"; // Define template variables @use "hugo:vars" as h; // note: modified for dart-sass // Include default variable overrides @import "common/variables-dart.scss"; // note: modified for dart-sass @import "theme/variables.scss"; @import "common/icons.scss"; // Import custom utilities (must be before Bootstrap) @import "common/utilities-custom.scss"; // Import Bootstrap configuration (mounted by core Bootstrap module) @import "bootstrap-dart.scss"; // note: modified for dart-sass // Import responsive utilities (requires Bootstrap variables to be defined) @import "common/utilities-responsive.scss"; // Include dark mode overrides @import "common/variables-dark.scss"; // Import Hinode theme styles @import "components/abbr.scss"; @import "components/alert.scss"; @import "components/blockquote.scss"; @import "components/button.scss"; @import "components/card.scss"; @import "components/carousel.scss"; @import "components/clipboard.scss"; @import "components/command.scss"; @import "components/docs.scss"; @import "components/feature.scss"; @import "components/footer.scss"; @import "components/kbd.scss"; @import "components/nav.scss"; @import "components/navbar.scss"; @import "components/img.scss"; @import "components/pagination.scss"; @import "components/persona.scss"; @import "components/popover.scss"; @import "components/sidebar.scss"; @import "components/syntax-dart.scss"; // note: modified for dart-sass @import "components/table.scss"; @import "components/testimonial.scss"; @import "components/toast.scss"; @import "components/timeline.scss"; @import "components/toc.scss"; @import "components/tooltip.scss"; @import "components/video.scss"; @import "common/animation.scss"; @import "common/masonry.scss"; @import "common/scrollbar.scss"; @import "common/styles.scss"; @import "layouts/reboot.scss"; @import "layouts/type.scss"; @import "common/export.scss"; @import "helpers/colored-links.scss"; @import "helpers/display.scss"; // note: modified for dart-sass @if h.$import-fonts { @include meta.load-css(theme/fonts); } // Import theme placeholders @import "theme/base.scss"; @import "theme/theme.scss"; // Import Bootstrap utilities API (mounted by core Bootstrap module) @import "modules/bootstrap/utilities/api"; ================================================ FILE: assets/scss/app.scss ================================================ // Define template variables @import "hugo:vars"; // Include default variable overrides @import "common/variables.scss"; @import "theme/variables.scss"; @import "common/icons.scss"; // Import custom utilities (must be before Bootstrap) @import "common/utilities-custom.scss"; // Import Bootstrap configuration (mounted by core Bootstrap module) @import "bootstrap.scss"; // Import responsive utilities (requires Bootstrap variables to be defined) @import "common/utilities-responsive.scss"; // Include dark mode overrides @import "common/variables-dark.scss"; // Import Hinode theme styles @import "components/abbr.scss"; @import "components/alert.scss"; @import "components/blockquote.scss"; @import "components/button.scss"; @import "components/card.scss"; @import "components/carousel.scss"; @import "components/clipboard.scss"; @import "components/command.scss"; @import "components/docs.scss"; @import "components/feature.scss"; @import "components/footer.scss"; @import "components/kbd.scss"; @import "components/nav.scss"; @import "components/navbar.scss"; @import "components/img.scss"; @import "components/pagination.scss"; @import "components/persona.scss"; @import "components/popover.scss"; @import "components/sidebar.scss"; @import "components/syntax.scss"; @import "components/table.scss"; @import "components/testimonial.scss"; @import "components/toast.scss"; @import "components/timeline.scss"; @import "components/toc.scss"; @import "components/tooltip.scss"; @import "components/video.scss"; @import "common/animation.scss"; @import "common/masonry.scss"; @import "common/scrollbar.scss"; @import "common/styles.scss"; @import "layouts/reboot.scss"; @import "layouts/type.scss"; @import "common/export.scss"; @import "helpers/colored-links.scss"; @import "helpers/display.scss"; {{ if (not (hasPrefix (lower site.Params.style.themeFontPath) "http")) }} @import "theme/fonts.scss"; {{ end }} // Import theme placeholders @import "theme/base.scss"; @import "theme/theme.scss"; // Import Bootstrap utilities API (mounted by core Bootstrap module) @import "modules/bootstrap/utilities/api"; ================================================ FILE: assets/scss/common/_animation.scss ================================================ .rotate-5 { transform: rotate(5deg); } .rotate-n5 { transform: rotate(-5deg); } @media (prefers-reduced-motion: no-preference) { .reveal { position: relative; opacity: 0; animation-iteration-count: 1; } .reveal.active { opacity: 1; } .active.fade-bottom { animation: fade-bottom 1s ease-in; } .active.fade-bottom-5 { animation: fade-bottom-5 1s ease-in; } .active.fade-bottom-n5 { animation: fade-bottom-n5 1s ease-in; } .active.fade-left { animation: fade-left 1s ease-in; } .active.fade-right { animation: fade-right 1s ease-in; } @keyframes fade-bottom { 0% { transform: translateY(50px); opacity: 0; } 100% { transform: translateY(0); opacity: 1; } } @keyframes fade-bottom-5 { 0% { transform: translateY(50px) rotate(5deg); opacity: 0; } 100% { transform: translateY(0) rotate(5deg); opacity: 1; } } @keyframes fade-bottom-n5 { 0% { transform: translateY(50px) rotate(-5deg); opacity: 0; } 100% { transform: translateY(0) rotate(-5deg); opacity: 1; } } @keyframes fade-left { 0% { transform: translateX(-100px); opacity: 0; } 100% { transform: translateX(0); opacity: 1; } } @keyframes fade-right { 0% { transform: translateX(100px); opacity: 0; } 100% { transform: translateX(0); opacity: 1; } } } ================================================ FILE: assets/scss/common/_export.scss ================================================ // stylelint-disable selector-pseudo-class-no-unknown // scss-docs-start export :hinode-theme { --accordion-icon-active-color: #{$accordion-icon-active-color}; --accordion-icon-active-color-dark: #{$gray-300}; --accordion-icon-color: #{$accordion-icon-color}; --accordion-icon-color-dark: #{$gray-600}; --btn-close-color: #{$btn-close-color}; --btn-toggle-color: #{$btn-toggle-color}; --btn-toggle-color-dark: #{$gray-600}; --carousel-control-color: #{$carousel-control-color}; --form-check-input-checked-color: #{$form-check-input-checked-color}; --form-check-input-indeterminate-color: #{$form-check-input-indeterminate-color}; --form-feedback-icon-invalid-color: #{$form-feedback-icon-invalid-color}; --form-feedback-icon-valid-color: #{$form-feedback-icon-valid-color}; --form-select-indicator-color: #{$form-select-indicator-color}; --form-select-indicator-color-dark: #{$form-select-indicator-color-dark}; --form-switch-checked-color: #{$form-switch-checked-color}; --form-switch-color: #{$form-switch-color}; --form-switch-color-dark: #{$form-switch-color-dark}; --form-switch-focus-color: #{$form-switch-focus-color}; --navbar-dark-color: #{$navbar-dark-color}; --navbar-light-icon-color: rgba($body-color, 0.75); // TODO: See https://github.com/twbs/bootstrap/pull/37720 } // scss-docs-end export // stylelint-enable selector-pseudo-class-no-unknown ================================================ FILE: assets/scss/common/_icons.scss ================================================ // scss-docs-start icons $form-check-input-checked-bg-image: url("#{$base-url}icons/form-check-input-checked-bg-image.svg") !default; $form-check-radio-checked-bg-image: url("#{$base-url}icons/form-check-radio-checked-bg-image.svg") !default; $form-check-input-indeterminate-bg-image: url("#{$base-url}icons/form-check-input-indeterminate-bg-image.svg") !default; $form-switch-bg-image: url("#{$base-url}icons/form-switch-bg-image.svg") !default; $form-switch-bg-image-dark: url("#{$base-url}icons/form-switch-bg-image-dark.svg") !default; $form-switch-focus-bg-image: url("#{$base-url}icons/form-switch-focus-bg-image.svg") !default; $form-switch-checked-bg-image: url("#{$base-url}icons/form-switch-checked-bg-image.svg") !default; $form-select-indicator: url("#{$base-url}icons/form-select-indicator.svg") !default; $form-select-indicator-dark: url("#{$base-url}icons/form-select-indicator-dark.svg") !default; $form-feedback-icon-valid: url("#{$base-url}icons/form-feedback-icon-valid.svg") !default; $form-feedback-icon-invalid: url("#{$base-url}icons/form-feedback-icon-invalid.svg") !default; $navbar-light-toggler-icon-bg: url("#{$base-url}icons/navbar-light-toggler-icon-bg.svg") !default; $navbar-dark-toggler-icon-bg: url("#{$base-url}icons/navbar-dark-toggler-icon-bg.svg") !default; $accordion-button-icon: url("#{$base-url}icons/accordion-button-icon.svg") !default; $accordion-button-icon-dark: url("#{$base-url}icons/accordion-button-icon-dark.svg") !default; $accordion-button-active-icon: url("#{$base-url}icons/accordion-button-active-icon.svg") !default; $accordion-button-active-icon-dark: url("#{$base-url}icons/accordion-button-active-icon-dark.svg") !default; $carousel-control-prev-icon-bg: url("#{$base-url}icons/carousel-control-prev-icon-bg.svg") !default; $carousel-control-next-icon-bg: url("#{$base-url}icons/carousel-control-next-icon-bg.svg") !default; $btn-close-bg: url("#{$base-url}icons/btn-close-bg.svg") !default; $btn-toggle: url("#{$base-url}icons/btn-toggle.svg") !default; $btn-toggle-dark: url("#{$base-url}icons/btn-toggle-dark.svg") !default; // scss-docs-end icons ================================================ FILE: assets/scss/common/_masonry.scss ================================================ .masonry { --masonry-padding: 4px; } .m-row { display: flex; flex-wrap: wrap; padding: 0 var(--masonry-padding); } .m-col { flex: 100%; max-width: 100%; padding: 0 var(--masonry-padding); } .m-col div { margin-top: calc(2 * var(--masonry-padding)); border-radius: #{$theme-border-radius} if($enable-important-utilities, !important, null); } ================================================ FILE: assets/scss/common/_scrollbar.scss ================================================ @mixin scrollbar( $foreground-color: var(--bs-primary), $background-color: var(--bs-tertiary-bg), $size: 10px ) { // For Safari and Chrome (to force appearance in Chrome) &::-webkit-scrollbar { width: $size; height: $size; } &::-webkit-scrollbar-thumb { border-radius: calc($size / 2); background: $foreground-color; } &::-webkit-scrollbar-track { border-radius: calc($size / 2); background: $background-color; } // Standard version (Firefox, only appears on scroll) @supports (-moz-appearance:none) { /* stylelint-disable-next-line no-invalid-position-declaration */ scrollbar-color: $foreground-color $background-color; } } .scrollbar-horizontal { @include scrollbar; overflow-x: scroll; margin: auto; } ================================================ FILE: assets/scss/common/_styles.scss ================================================ @if $enable-dark-mode { [data-bs-theme-animate="true"] body { transition: background-color 0.5s, color 0.5s; } } // // Remove underline from all links // a:link, a:visited, a:hover, a:active { text-decoration: none; } div.rounded, img.rounded { --bs-border-radius: #{$theme-border-radius}; } // // Sticky-footer: body fills at least the full viewport; .main grows to fill // remaining space, pushing the footer to the bottom without JS measurement. // body { display: flex; flex-direction: column; min-height: 100dvh; } // // Ensure main page is rendered to full viewport height // .main { --navbar-height: #{$navbar-height}; --overlay-offset: #{$overlay-offset}; --section-height: 88vh; --max-section-height: 1024px; flex: 1; } // Fixed navbar is out of flow: offset .main so content starts below the navbar .navbar-fixed .main { margin-top: var(--navbar-offset); } // footerBelowFold: push footer just past the viewport edge. // Fixed (--navbar-offset = navbar height): margin-top = --navbar-offset, so subtract once. // Non-fixed (--navbar-offset = 0): navbar is in flow; subtract --navbar-height (actual height, // always set from site.Params.navigation.offset regardless of the fixed setting). .navbar-fixed.footer-below-fold .main { min-height: calc(100vh - var(--navbar-offset)); } .footer-below-fold:not(.navbar-fixed) .main { min-height: calc(100vh - var(--navbar-height)); } main:has(section:first-of-type.section-cover), main:has(section:first-of-type.background-container) { margin-top: var(--overlay-offset); } .overlay-spacer { padding-top: var(--navbar-height); } .tickmark li::marker { content: "✓ "; } .anchor { color: transparent; } .heading:hover .anchor { transition: 0.25s ease-in-out; color: $primary; } :root { --nav-height: 90px; } .section-cover { min-height: calc(var(--section-height) - var(--overlay-offset)); } .hero-title { width: 100%; } @include media-breakpoint-up(xxl) { .section-cover { min-height: calc(min(calc(var(--section-height) - var(--overlay-offset)), var(--max-section-height))); } } /* stylelint-disable media-feature-range-notation */ @media (min-height: 1400px) { .section-cover { min-height: calc(min(calc(var(--section-height) - var(--overlay-offset)), var(--max-section-height))); } } /* stylelint-enable media-feature-range-notation */ .width-100 { width: 100%; } ================================================ FILE: assets/scss/common/_utilities-custom.scss ================================================ // Custom Bootstrap utilities extensions // This file must be imported BEFORE bootstrap.scss to ensure utilities are processed // Initialize utilities map if not already defined $utilities: () !default; // Add custom masonry column utilities $utilities: map-merge( $utilities, ( "m-col": ( property: max-width, responsive: true, class: m-col, values: ( 1: 100%, 2: 50%, 3: 33.3%, 4: 25%, 5: 20%, ) ) ) ); // Add custom margin utilities (mx auto/0) $utilities: map-merge( $utilities, ( "cursor": ( property: margin-left margin-right, class: mx, responsive: true, values: auto 0, ) ) ); // Add wide padding utilities (using hardcoded rem values since $spacer not yet available) $utilities: map-merge( $utilities, ( "padding-start-wide": ( property: padding-left, responsive: true, class: psw, values: ( 0: 0, 1: 1.5rem, 2: 3rem, 3: 6rem, 4: 9rem, 5: 12rem, ) ), "padding-top-wide": ( property: padding-top, responsive: true, class: ptw, values: ( 0: 0, 1: 1.5rem, 2: 3rem, 3: 6rem, 4: 9rem, 5: 12rem, ) ), "width": ( property: width, responsive: true, values: ( auto: auto ) ) ) ); ================================================ FILE: assets/scss/common/_utilities-responsive.scss ================================================ // Responsive utilities that require Bootstrap variables to be defined // Must be imported AFTER bootstrap.scss // Make the font-size class responsive (requires $font-sizes from Bootstrap) $utilities: map-merge( $utilities, ( "font-size": ( responsive: true, rfs: true, property: font-size, class: fs, values: $font-sizes ), ) ); ================================================ FILE: assets/scss/common/_variables-dark.scss ================================================ @if $enable-dark-mode { @include color-mode(dark) { --bs-primary: #{$primary-text-emphasis-dark}; --bs-secondary: #{$secondary-text-emphasis-dark}; --bs-primary-dark: #{$primary-bg-subtle-dark}; --bs-primary-bg-subtle: #{$primary-bg-subtle-dark}; --bg-primary-subtle: rgba(var(--bs-primary-rgb), var(--bs-link-opacity, 0.1)); --bs-body: var(--bs-body-bg); --bs-body-tertiary: var(--bs-tertiary-bg); .bg-primary-subtle { background-color: var(--bg-primary-subtle) if($enable-important-utilities, !important, null); } .accordion-button { background-color: var(--bg-primary-subtle); } .dropdown-item { --bs-dropdown-link-hover-bg: var(--bs-tertiary-bg); } .form-check-input:checked { background-color: var(--bs-primary); border-color: var(--bs-primary); } .form-check-input[type="checkbox"]:indeterminate { background-color: var(--bs-primary); border-color: var(--bs-primary); } .form-range::-webkit-slider-thumb { background-color: var(--bs-primary); } .form-range::-moz-range-thumb { background-color: var(--bs-primary); } .alert-primary { --bs-alert-bg: var(--bg-primary-subtle); } .btn-outline-primary { --bs-btn-color: var(--bs-primary); --bs-btn-border-color: var(--bs-primary); --bs-btn-hover-bg: var(--bs-primary); --bs-btn-hover-border-color: var(--bs-primary); --bs-btn-active-bg: var(--bs-primary); --bs-btn-active-border-color: var(--bs-primary); --bs-btn-disabled-color: var(--bs-primary); --bs-btn-disabled-border-color: var(--bs-primary); } .btn-outline-secondary { --bs-btn-color: var(--bs-secondary); --bs-btn-border-color: var(--bs-secondary); --bs-btn-hover-bg: var(--bs-secondary); --bs-btn-hover-border-color: var(--bs-secondary); --bs-btn-active-bg: var(--bs-secondary); --bs-btn-active-border-color: var(--bs-secondary); --bs-btn-disabled-color: var(--bs-secondary); --bs-btn-disabled-border-color: var(--bs-secondary); } .link-primary { color: var(--bs-primary) if($enable-important-utilities, !important, null); text-decoration-color: var(--bs-primary) if($enable-important-utilities, !important, null); &:hover, &:focus { color: var(--bs-primary-dark) if($enable-important-utilities, !important, null); text-decoration-color: var(--bs-primary-dark) if($enable-important-utilities, !important, null); } } .pagination { --bs-pagination-color: var(--bs-body-bg); --bs-pagination-bg: var(--bs-primary); } .progress, .progress-stacked { --bs-progress-bar-bg: var(--bs-primary); } .list-group { --bs-list-group-active-bg: var(--bs-primary); --bs-list-group-active-border-color: var(--bs-primary); } .clipboard-button:hover { color: var(--bs-primary); } .clipboard-button:hover > svg { fill: var(--bs-primary); } .toggler-icon { background-color: var(--bs-primary); } .heading:hover .anchor { color: var(--bs-primary); } } } ================================================ FILE: assets/scss/common/_variables-dart.scss ================================================ // Bootstrap variables overrides for theme $enable-negative-margins: true; $enable-important-utilities: true !default; // Remove the border from the focused navigation toggler $navbar-toggler-focus-width: 0 !default; $base-url: h.$base-url; $font-family-sans-serif: h.$theme-font, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default; $font-size-base: h.$font-size-base !default; $headings-font-weight: 600 !default; $font-weight-lighter: lighter !default; $font-weight-light: 200 !default; $font-weight-normal: 300 !default; $font-weight-bold: 600 !default; $font-weight-bolder: bolder !default; strong { font-weight: 600 if($enable-important-utilities, !important, null); } $theme-border-radius: 0.375rem; $navbar-height: h.$navbar-height; $navbar-offset: h.$navbar-offset; $navbar-offset-xs: h.$navbar-offset-xs; $navbar-size: h.$navbar-size; $overlay-offset: h.$overlay-offset; $primary: h.$primary; $secondary: h.$secondary; $success: h.$success; $info: h.$info; $warning: h.$warning; $danger: h.$danger; $light: h.$light; $dark: h.$dark; $white: #fff !default; $black: #000 !default; $body-bg: #fff !default; $gray-100: #f8f9fa !default; $btn-toggle-color: $black !default; $carousel-dark-indicator-active-bg: #fff !default; $carousel-dark-caption-color: #fff !default; $carousel-dark-control-icon-filter: invert(0) grayscale(100) !default; $primary-text-emphasis-dark: mix(white, h.$primary, h.$dark-mode-tint) !default; $secondary-text-emphasis-dark: mix(white, h.$secondary, h.$dark-mode-tint) !default; $link-color-dark: mix(white, h.$primary, h.$dark-mode-tint) !default; $primary-bg-subtle-dark: mix(black, h.$primary, h.$dark-mode-shade) !default; $primary-border-subtle-dark: mix(black, h.$primary, calc(h.$dark-mode-shade / 2)) !default; $dropdown-transition: opacity .15s ease-in-out !default; $dropdown-horizontal-margin-top: calc((-1.5 * 1rem) - 2px); $dropdown-horizontal-padding-y: calc(1rem + 2px); $theme-colors: ( "primary": $primary, "secondary": $secondary, "success": $success, "info": $info, "warning": $warning, "danger": $danger, "light": $light, "dark": $dark, "white": $white, "black": $black, "body": $body-bg, "body-tertiary": $gray-100, ); $btn-padding-y-xs: .08rem !default; $btn-padding-x-xs: 0.3rem !default; $btn-font-size-xs: $font-size-base * .6 !default; $btn-border-radius-xs: .2rem !default; // Padding settings $padding-x: h.$padding-x; $padding-y: h.$padding-y; ================================================ FILE: assets/scss/common/_variables.scss ================================================ // Bootstrap variables overrides for theme $enable-negative-margins: true; $enable-important-utilities: true !default; // Remove the border from the focused navigation toggler $navbar-toggler-focus-width: 0 !default; $base-url: $base-url; // scss-docs-start font $font-family-sans-serif: $theme-font, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default; $font-size-base: $font-size-base !default; $headings-font-weight: 600 !default; $font-weight-lighter: lighter !default; $font-weight-light: 200 !default; $font-weight-normal: 300 !default; $font-weight-bold: 600 !default; $font-weight-bolder: bolder !default; strong { font-weight: 600 if($enable-important-utilities, !important, null); } // scss-docs-end font $theme-border-radius: 0.375rem; $tooltip-border-radius: $theme-border-radius; $white: #fff !default; $black: #000 !default; $body-bg: #fff !default; $gray-100: #f8f9fa !default; $btn-toggle-color: $black !default; $card-color: var(--bs-body-color); $carousel-dark-indicator-active-bg: #fff !default; $carousel-dark-caption-color: #fff !default; $carousel-dark-control-icon-filter: invert(0) grayscale(100) !default; // scss-docs-start color-mode $primary-text-emphasis-dark: mix(white, $primary, $dark-mode-tint) !default; $secondary-text-emphasis-dark: mix(white, $secondary, $dark-mode-tint) !default; $link-color-dark: mix(white, $primary, $dark-mode-tint) !default; $primary-bg-subtle-dark: mix(black, $primary, $dark-mode-shade) !default; $primary-border-subtle-dark: mix(black, $primary, $dark-mode-shade / 2) !default; // scss-docs-end color-mode // scss-docs-start horizontal-nav $dropdown-transition: opacity .15s ease-in-out !default; $dropdown-horizontal-margin-top: calc((-1.5 * 1rem) - 2px); $dropdown-horizontal-padding-y: calc(1rem + 2px); // scss-docs-end horizontal-nav $theme-colors: ( "primary": $primary, "secondary": $secondary, "success": $success, "info": $info, "warning": $warning, "danger": $danger, "light": $light, "dark": $dark, "white": $white, "black": $black, "body": $body-bg, "body-tertiary": $gray-100, ); $btn-padding-y-xs: .08rem !default; $btn-padding-x-xs: 0.3rem !default; $btn-font-size-xs: $font-size-base * .6 !default; $btn-border-radius-xs: .2rem !default; // Padding settings $padding-x: $padding-x; $padding-y: $padding-y; ================================================ FILE: assets/scss/components/_abbr.scss ================================================ @media (hover: none) { abbr[title] { position: relative; text-decoration: underline dotted; } abbr[title]:hover::after, abbr[title]:focus::after { content: attr(title); position: absolute; left: 0; bottom: -30px; width: auto; white-space: nowrap; background-color: var(--bs-body-bg); color: var(--bs-tooltip-color); border-radius: 3px; box-shadow: 1px 1px 5px 0 rgba(0,0,0,0.4); font-size: 14px; padding: 3px 5px; } } ================================================ FILE: assets/scss/components/_alert.scss ================================================ .alert code { color: inherit; } /* stylelint-disable declaration-block-no-redundant-longhand-properties */ .alert a { color: inherit; &:link, &:visited, &:hover, &:active { text-decoration-line: underline; text-decoration-style: dotted; text-decoration-color: var(--bs-body); } } /* stylelint-enable declaration-block-no-redundant-longhand-properties */ ================================================ FILE: assets/scss/components/_blockquote.scss ================================================ .blockquote { border-left: 0.3rem solid; border-color: $secondary; padding: 1rem 1.5rem; } .blockquote-alert { --bs-blockquote-alert-color: #{$secondary}; border-left: 0.3rem solid; border-color: var(--bs-blockquote-alert-color); padding: .5rem 1.5rem; } .blockquote-alert > p:nth-of-type(2) { margin-bottom: 0; } .blockquote-alert-heading { font-weight: bold; color: var(--bs-blockquote-alert-color); } .blockquote-alert-caution { --bs-blockquote-alert-color: var(--#{$prefix}danger); } .blockquote-alert-important { --bs-blockquote-alert-color: var(--#{$prefix}primary); } .blockquote-alert-note { --bs-blockquote-alert-color: var(--#{$prefix}info); } .blockquote-alert-tip { --bs-blockquote-alert-color: var(--#{$prefix}success); } .blockquote-alert-warning { --bs-blockquote-alert-color: var(--#{$prefix}warning); } .blockquote-alert a.btn-link { --bs-link-color: var(--bs-blockquote-alert-color); --bs-link-hover-color: color-mix(in srgb, var(--bs-link-color), black 20%); color: var(--bs-link-color) !important; &:hover, &:focus { color: var(--bs-link-hover-color) !important; } } ================================================ FILE: assets/scss/components/_button.scss ================================================ /* Set hover color for primary button to white (overrides color contrast defined in mixin) */ .btn-outline-primary:hover, .btn-primary:focus, .btn-primary:active, .btn-primary.active, .open > .dropdown-toggle.btn-primary { color: #fff if($enable-important-utilities, !important, null); } .btn-social { background-color: transparent; --bs-btn-bg: transparent; --bs-btn-border-width: none; --bs-btn-color: var(--bs-secondary); --bs-btn-border-color: none; --bs-btn-hover-bg: none; --bs-btn-hover-border-color: none; --bs-btn-active-bg: none; --bs-btn-active-border-color: none; } .btn-social:hover, .btn-social:focus, .btn-social:active, .btn-social.active, .open > .dropdown-toggle.btn-primary { background-color: transparent; color: var(--bs-primary) if($enable-important-utilities, !important, null); } a.btn { margin-top: $spacer * .25; margin-bottom: $spacer * .25; } .btn-close { background-color: transparent if($enable-important-utilities, !important, null); background-image: var(--#{$prefix}btn-close-bg) if($enable-important-utilities, !important, null); background-position: center if($enable-important-utilities, !important, null); background-repeat: no-repeat if($enable-important-utilities, !important, null); background-size: $btn-close-width if($enable-important-utilities, !important, null); } .btn-link { --bs-btn-padding-x: 0; --bs-btn-padding-y: 0; margin: 0 !important; } .btn-xs { @include button-size($btn-padding-y-xs, $btn-padding-x-xs, $btn-font-size-xs, $btn-border-radius-xs); } .btn { --bs-border-radius: #{$theme-border-radius}; } ================================================ FILE: assets/scss/components/_card.scss ================================================ // add zoom animation with opacity change on card img hover // source: https://stackoverflow.com/a/43816376 .card-img-bg { background-color: var(--#{$prefix}secondary-bg); } .card { --bs-card-border-radius: #{$theme-border-radius}; --bs-card-inner-border-radius: #{$theme-border-radius}; --bs-border-radius: #{$theme-border-radius}; --bs-card-bg: transparent; } .card .card-img-wrap { overflow: hidden; position: relative; } .card .card-img-wrap:has(.card-img-top) { border-top-left-radius: var(--#{$prefix}card-inner-border-radius); border-top-right-radius: var(--#{$prefix}card-inner-border-radius); } .card .card-img-wrap:has(.card-img-bottom) { border-bottom-right-radius: var(--#{$prefix}card-inner-border-radius); border-bottom-left-radius: var(--#{$prefix}card-inner-border-radius); } .card-zoom { cursor: pointer; } .card-img-top { --bs-border-radius: #{$theme-border-radius}; border-top-left-radius: var(--bs-border-radius) !important; border-top-right-radius: var(--bs-border-radius) !important; } .card-img-wrap img { transition: transform 0.25s ease; width: 100%; } .card-icon { color: $secondary; } .card-zoom::after .card-img-wrap img { content: ""; position: absolute; inset: 0; background: rgba(255, 255, 255, 0.3); opacity: 0; transition: opacity 0.25s; } .card-zoom:hover .card-img-wrap img { transform: scale(1.1); opacity: 0.5; } .card-zoom:hover::after .card-img-wrap img { opacity: 1; } .card-emphasize { transition: 0.3s transform cubic-bezier(0.155, 1.105, 0.295, 1.12), 0.3s box-shadow, 0.3s -webkit-transform cubic-bezier(0.155, 1.105, 0.295, 1.12); cursor: pointer; } .card-emphasize:hover { transform: scale(1.01); box-shadow: 0 10px 20px rgba(0, 0, 0, 0.12), 0 4px 8px rgba(0, 0, 0, 0.06); } .card-minimal { border: none; font-weight: bold; &:hover, &:focus { text-decoration: underline; } } // stylelint-disable annotation-no-unknown .card-body-link { color: $body-color if($enable-important-utilities, !important, null); } .card-body-margin { margin-bottom: $spacer * 1.5; // equals mb-4 } @if $enable-dark-mode { @include color-mode(dark) { .card-body-link { color: $gray-500 if($enable-important-utilities, !important, null); } } } .card-img-overlay .card-body-link { margin-top: auto; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; } .card-zoom .card-body-link { &:hover, &:focus { color: shade-color($primary, $link-shade-percentage) if($enable-important-utilities, !important, null); } } @if $enable-dark-mode { @include color-mode(dark) { .card-zoom .card-body-link { &:hover, &:focus { color: $primary-bg-subtle-dark if($enable-important-utilities, !important, null); } } } } // stylelint-enable annotation-no-unknown // make tag-link and card-button clickable on top of the stretched-link. .card .tag-link, .card .card-button { z-index: 2; position: relative; } .card-button-link { text-decoration: underline if($enable-important-utilities, !important, null); } // support horizontally scrollable card groups .card-container-wrapper { position: relative; } div.card-container-wrapper::after { content: ""; position: absolute; inset: 0; height: calc(100% - 2rem); background: linear-gradient( 90deg, var(--bs-body-bg) 0%, transparent 1.5rem, transparent calc(100% - 1.5rem), var(--bs-body-bg) 100% ); pointer-events: none; } .card-container { padding-left: 1.5rem; padding-right: 1.5rem; gap: 1.5rem; margin-bottom: 2rem; scroll-snap-type: x proximity; } .card-block-1 { width: 80%; scroll-snap-align: center; } .card-block-2 { width: 40%; scroll-snap-align: center; } .card-block-3 { width: 27%; scroll-snap-align: center; } .card-block-4 { width: 20%; scroll-snap-align: center; } .card-block-5 { width: 16%; scroll-snap-align: center; } // Hover link icon: appears on card hover/focus to signal clickability .card-link-icon { display: inline-flex; align-items: center; opacity: 0; transform: translateX(-4px); transition: opacity 0.2s ease, transform 0.2s ease; vertical-align: middle; font-size: 0.75em; margin-left: 0.25rem; } .card:hover .card-link-icon, .card:focus-within .card-link-icon { opacity: 1; transform: translateX(0); } ================================================ FILE: assets/scss/components/_carousel.scss ================================================ .carousel-inner { border-radius: #{$theme-border-radius}; } .gradient { width: 100%; height: 100%; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.3); } ================================================ FILE: assets/scss/components/_clipboard.scss ================================================ // Adapted from https://simplernerd.com/hugo-add-copy-to-clipboard-button/ .clipboard-button { position: absolute; right: 0; padding: 2px 7px 5px; margin: 5px; color: $secondary; background-color: transparent; border-style: none; font-size: 0.8em; z-index: 1; opacity: 0; transition: 0.1s; } .clipboard-button > svg { fill: $secondary; } .clipboard-button:hover { cursor: pointer; color: $primary; } .clipboard-button:hover > svg { fill: $primary; } .clipboard-button:focus { outline: 0; } .highlight { position: relative; } .highlight:hover > .clipboard-button { opacity: 1; transition: 0.2s; } ================================================ FILE: assets/scss/components/_command.scss ================================================ /* Adapted from PrismJS 1.29.0 https://prismjs.com/download.html#themes=prism&plugins=command-line */ /** * prism.js default theme for JavaScript, CSS and HTML * Based on dabblet (http://dabblet.com) * @author Lea Verou */ .command-line-prompt { border-right: 1px solid #999; display: block; float: left; font-size: 100%; letter-spacing: -1px; margin-right: 1em; pointer-events: none; text-align: right; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .command-line-prompt > span::before { opacity: 0.7; content: " "; display: block; padding-right: 0.8em; } .command-line-prompt > span[data-prompt]::before { content: attr(data-prompt); } .command-line-prompt > span[data-continuation-prompt]::before { content: attr(data-continuation-prompt); } .command-line span.token.output { /* Make shell output lines a bit lighter to distinguish them from shell commands */ opacity: 0.7; } ================================================ FILE: assets/scss/components/_docs.scss ================================================ .docs-controls .nav-link, .file-controls .nav-link { border-top-left-radius: #{$theme-border-radius}; border-top-right-radius: #{$theme-border-radius}; margin-left: #{$theme-border-radius}; } .docs-panel, .file-panel { border: 1px solid var(--#{$prefix}border-color); overflow: hidden; } .docs-panel, .docs-panel .collapse, .file-panel, .file-panel .collapse { border-radius: #{$theme-border-radius}; } ================================================ FILE: assets/scss/components/_feature.scss ================================================ .feature { margin-top: calc(0.3 * var(--navbar-offset)); } ================================================ FILE: assets/scss/components/_footer.scss ================================================ .footer { // background-color: $gray-800 if($enable-important-utilities, !important, null); color: var(--bs-secondary) if($enable-important-utilities, !important, null); } .link-bg-footer { color: var(--bs-secondary) if($enable-important-utilities, !important, null); &:hover, &:focus { color: var(--bs-tertiary-color) if($enable-important-utilities, !important, null); } } @if $enable-dark-mode { @include color-mode(dark) { .footer { color: $gray-500 if($enable-important-utilities, !important, null); } .link-bg-footer { color: $gray-500 if($enable-important-utilities, !important, null); &:hover, &:focus { color: $gray-400 if($enable-important-utilities, !important, null); } } } } ================================================ FILE: assets/scss/components/_img.scss ================================================ .img-wrap { overflow: hidden; position: relative; } .img-wrap img { height: 100%; width: 100%; object-fit: cover; } .card-img-h100 { width: auto; height: 100%; object-fit: cover; } .mirrorred { -webkit-transform: scaleX(-1); transform: scaleX(-1); } .background-img { --overlay-offset: #{$overlay-offset}; height: calc(100vh - var(--overlay-offset)); width: 100vw; object-fit: cover; } .figure-caption { margin-left: #{$theme-border-radius}; } ================================================ FILE: assets/scss/components/_kbd.scss ================================================ // scss-docs-start kbd kbd { border-radius: #{$theme-border-radius}; } // scss-docs-end kbd ================================================ FILE: assets/scss/components/_nav.scss ================================================ .nav-tabs { border: none !important; } .nav-callout, .tab-content { --#{$prefix}nav-callout-bg: var(--#{$prefix}body-bg); --#{$prefix}nav-callout-active-bg: var(--bs-primary-bg-subtle); --#{$prefix}nav-callout-gap: #{$nav-underline-gap}; column-gap: var(--#{$prefix}nav-callout-gap) !important; } .nav-callout + .tab-content { background-color: var(--#{$prefix}nav-callout-bg); padding: 2 * $spacer; margin-top: 0 !important; } .nav-callout .nav-link { display: flex; text-align: start; vertical-align: text-top; border-radius: 0; padding: 0 0 (4 * $spacer); border-bottom: none; position: relative; } .nav-callout .nav-link.active { background-image: linear-gradient(to top right, var(--#{$prefix}nav-callout-bg) 50%, transparent 0); background-size: 50% (3 * $spacer); background-repeat: no-repeat; background-position: 50% bottom; font-weight: 600; color: var(--bs-nav-underline-link-active-color); // Diagonal border line &::before { content: ""; position: absolute; bottom: 0; left: 25%; width: 50%; height: (3 * $spacer); background: linear-gradient( to top right, transparent calc(50% - 0.5px), var(--#{$prefix}border-color) calc(50% - 0.5px), var(--#{$prefix}border-color) calc(50% + 0.5px), transparent calc(50% + 0.5px) ); pointer-events: none; } // Left border only &::after { content: ""; position: absolute; bottom: 0; left: 25%; width: 50%; height: (3 * $spacer); border-left: 1px solid var(--#{$prefix}border-color); pointer-events: none; } } .nav-callout .accordion-button { background-color: var(--#{$prefix}nav-callout-bg) !important; border: solid; border-color: var(--#{$prefix}border-color); border-radius: var(--#{$prefix}accordion-inner-border-radius) !important; margin-bottom: 0; &:focus { border-bottom: none !important; box-shadow: none; } &:not(.collapsed) { box-shadow: none; } } .nav-callout .accordion-item { margin-top: 2 * $spacer; margin-bottom: 2 * $spacer; border: none; } .nav-callout .accordion-button[aria-expanded="false"] { border-bottom: solid !important; border-color: var(--#{$prefix}border-color) !important; border-radius: var(--#{$prefix}accordion-inner-border-radius); } .nav-callout .accordion-button[aria-expanded="true"] { border-color: var(--#{$prefix}border-color) !important; border-bottom: none !important; border-radius: var(--#{$prefix}accordion-inner-border-radius) var(--#{$prefix}accordion-inner-border-radius) 0 0 !important; padding-bottom: 3 * $spacer; background-image: linear-gradient(to top right, var(--#{$prefix}nav-callout-active-bg) 50%, transparent 0); background-size: 10% (2.5 * $spacer); background-repeat: no-repeat; background-position: 10% bottom; } .nav-callout .accordion-collapse { background-color: var(--#{$prefix}nav-callout-active-bg) !important; border-radius: 0 0 var(--#{$prefix}accordion-inner-border-radius) var(--#{$prefix}accordion-inner-border-radius); border-top: none !important; border-left: solid; border-right: solid; border-bottom: solid; border-color: var(--#{$prefix}border-color); } .nav-callout, .pagination { --bs-border-radius: #{$theme-border-radius}; } .nav-callout .tab-content { border-radius: #{$theme-border-radius}; } @if $enable-dark-mode { @include color-mode(dark) { .nav-callout .accordion-button[aria-expanded="true"] { background-image: linear-gradient(to top right, shade-color($primary, 70%) 50%, transparent 0); } .nav-callout .accordion-collapse { background-color: shade-color($primary, 70%) !important; } } } ================================================ FILE: assets/scss/components/_navbar.scss ================================================ // stylelint-disable annotation-no-unknown // adapted from https://www.codeply.com/p/UsTEwDkzNp# .checkbox { opacity: 0; position: absolute; } .mode-switch { --#{$prefix}mode-switch-width: 3em; } .mode-switch .label { border-color: var(--#{$prefix}border-color); border-style: solid; border-width: 1px; border-radius: var(--#{$prefix}mode-switch-width); cursor: pointer; display: flex; align-items: center; justify-content: space-between; padding: 5px; position: relative; height: calc(1px + var(--#{$prefix}mode-switch-width) / 2); width: var(--#{$prefix}mode-switch-width); transform: scale(0.9); } .notransition { -webkit-transition: none !important; -moz-transition: none !important; -o-transition: none !important; transition: none !important; } .mode-switch .label .ball { background-color: var(--#{$prefix}border-color); border-radius: 50%; position: absolute; top: 2px; left: 2px; height: calc((var(--#{$prefix}mode-switch-width) / 2) - 5px); width: calc((var(--#{$prefix}mode-switch-width) / 2) - 5px); transition: transform 0.2s linear; } .mode-switch .checkbox:checked + .label .ball { transform: translateX(calc((var(--#{$prefix}mode-switch-width) / 2) - 1px)); } @if $enable-dark-mode { [data-bs-theme="light"] .mode-switch .ball { transform: translateX(calc((var(--#{$prefix}mode-switch-width) / 2) - 1px)); } } .mode-switch .fa-moon { color: $yellow; transform: scale(0.8); } .mode-switch .fa-sun { color: var(--#{$prefix}bs-body-color); transform: scale(0.8); } .mode-toggle > input { z-index: 1; cursor: pointer; height: 25px; width: 25px; } .mode-toggle > label { z-index: 0; cursor: pointer; } .mode-toggle .label svg { height: 1em; width: 1.25em; } // Source: https://jsfiddle.net/njhgr40m/ @if $enable-dark-mode { [data-bs-theme-animate="true"] .navbar { transition: 0.5s ease-in-out; } } .navbar { --bs-navbar-expanded-color: var(--bs-body-bg); --bs-navbar-toggler-color: var(--bs-navbar-hover-color); background-color: transparent; @each $state, $val in $theme-colors { --bs-navbar-color-#{$state}: #{$val}; } } .navbar[data-transparent="true"] { backdrop-filter: none; transition: all 0.3s ease; &.navbar-scrolled { backdrop-filter: blur(10px); } } .nav-active, .navbar-expanded { background-color: var(--bs-navbar-expanded-color); border-bottom: 1px solid var(--bs-secondary-bg); } .nav-link { margin: 0 .15rem; display: inline-flex; } .navbar-title, .navbar-title-center, .navbar-title-start { display: inline-block; white-space: normal; vertical-align: middle; padding: 0 $spacer; width: 100% !important; } .navbar-title, .navbar-title-center { text-align: center !important; } .navbar-contrast .nav-link.active, .navbar-contrast .nav-link.show, .navbar-contrast .nav-link:hover { border-bottom: solid 1px var(--bs-navbar-hover-color); margin-bottom: -1px; } .navbar-brand { margin-right: 0; } .navbar-contrast { --bs-navbar-color: white !important; --bs-navbar-hover-color: white !important; --bs-navbar-disabled-color: white !important; --bs-navbar-active-color: white !important; --bs-navbar-toggler-color: white; .navbar-title, .navbar-brand, .mode-switch { --#{$prefix}border-color: white; color: white !important; } .mode-switch .fa-moon { color: $white; } } .navbar-expanded { box-shadow: $box-shadow-sm; min-height: 100vh; align-items: start; } .navbar-expanded .navbar-collapse { margin-top: 2rem; } @each $h, $size in $font-sizes { .navbar-fs-#{$h} { font-size: #{$size}; } } @each $breakpoint in map-keys($grid-breakpoints) { $next: breakpoint-next($breakpoint, $grid-breakpoints); $infix: breakpoint-infix($next, $grid-breakpoints); @if $infix != '' { @include media-breakpoint-up($next) { .navbar#{$infix}-fs { font-size: inherit; } } } } .navbar-icon { padding-right: var(--bs-navbar-nav-link-padding-x); padding-left: var(--bs-navbar-nav-link-padding-x); } .nav-item .vr { color: var(--bs-navbar-color); } .navbar .nav-item { display: flex; align-items: center; white-space: nowrap; } .navbar-collapse:not(.show, .collapsing) .nav-item:first-of-type { // double padding between brand logo / search bar and first nav item // only apply when navbar is fully expanded (not toggled to show) padding-left: var(--bs-navbar-nav-link-padding-x); } // Remove padding when navbar is toggled open on small devices .navbar-collapse.show .nav-item:first-of-type { padding-left: 0; } .navbar-collapse .dropdown { display: inline; align-items: normal; } .navbar-expanded .btn { font-size: 1em; } .navbar .btn { border-radius: #{$theme-border-radius}; } .navbar-expanded .search-input { margin-bottom: 1rem; } /* Remove border from toggler */ .navbar-toggler { border: 0 if($enable-important-utilities, !important, null); } .navbar-toggler:focus, .navbar-toggler:active, .navbar-toggler-icon:focus { outline: none if($enable-important-utilities, !important, null); box-shadow: none if($enable-important-utilities, !important, null); border: 0 if($enable-important-utilities, !important, null); } .fw-30 { width: 30px !important; } /* Lines of the Toggler */ .toggler-icon { width: 30px; height: 3px; display: block; transition: all 0.2s; } /* Adds Space between the lines */ .middle-bar { margin: 5px auto; } /* State when navbar is opened (START) */ .navbar-toggler .top-bar { transform: rotate(45deg); transform-origin: 10% 10%; } .navbar-toggler .middle-bar { opacity: 0; filter: alpha(opacity=0); } .navbar-toggler .bottom-bar { transform: rotate(-45deg); transform-origin: 10% 90%; } /* State when navbar is opened (END) */ /* State when navbar is collapsed (START) */ .navbar-toggler.collapsed .top-bar { transform: rotate(0); } .navbar-toggler.collapsed .middle-bar { opacity: 1; filter: alpha(opacity=100); } .navbar-toggler.collapsed .bottom-bar { transform: rotate(0); } /* State when navbar is collapsed (END) */ /* Color of Toggler when collapsed */ .navbar-toggler.collapsed .toggler-icon { background-color: var(--bs-navbar-toggler-color); } .emphasis { background-color: var(--bs-navbar-toggler-color); } @include color-mode(dark) { .emphasis { background-color: $white if($enable-important-utilities, !important, null); } } // stylelint-enable annotation-no-unknown .navbar .dropdown-divider-bg { color: var(--#{$prefix}navbar-color); } :root { --dropdown-horizontal-bg: var(--#{$prefix}light); --navbar-offset: #{$navbar-offset-xs}; } .navbar-container { min-height: calc(2rem + 10px); width: 100% !important; } @include media-breakpoint-up(#{$navbar-size}) { :root { --navbar-offset: #{$navbar-offset}; } .navbar-container { width: auto !important; } .navbar-title { text-align: initial !important; padding: 0; } .navbar-brand { margin-right: var(--bs-navbar-brand-margin-end); } } @if $enable-dark-mode { @include color-mode(dark) { --dropdown-horizontal-bg: var(--#{$prefix}tertiary-bg); } } .dropdown-horizontal { @each $breakpoint in map-keys($grid-breakpoints) { $next: breakpoint-next($breakpoint, $grid-breakpoints); $infix: breakpoint-infix($next, $grid-breakpoints); @include media-breakpoint-up($next) { &#{$infix} { position: static !important; } &#{$infix} > .dropdown-menu { opacity: 0; display: block; visibility: hidden; background-color: var(--dropdown-horizontal-bg) if($enable-important-utilities, !important, null); width: 100%; height: auto; text-align: center; border-radius: 0; border: 0; margin-top: $dropdown-horizontal-margin-top; padding-top: $dropdown-horizontal-padding-y; padding-bottom: $dropdown-horizontal-padding-y; box-shadow: 0.125rem 0.25rem rgba(0, 0, 0, .075); @include transition($dropdown-transition); } &#{$infix} > .dropdown-menu.show { visibility: visible; opacity: 1; } &#{$infix} > .dropdown-menu > li { display: inline-block; padding-left: $spacer; padding-right: $spacer; } &#{$infix} > .dropdown-menu > li > a { padding-left: .25 * $spacer; padding-right: .25 * $spacer; &.active, &:hover, &:focus { color: var(--bs-body-color); border-bottom: solid 1px var(--bs-navbar-hover-color); margin-bottom: -1px; background-color: transparent; } } &#{$infix} > .nav-link.show { background-color: var(--dropdown-horizontal-bg) if($enable-important-utilities, !important, null); } } } } .navbar-overlay { position: absolute; z-index: $zindex-fixed; } .form-control.is-search { border: 1px solid var(--bs-border-color) !important; } .d-none-main-light, .d-none-inline-main-light { display: none !important; } .d-none-main-dark { display: block !important; } .d-none-inline-main-dark { display: inline !important; } [data-bs-main-theme="dark"] .d-none-main-light { display: block !important; } [data-bs-main-theme="dark"] .d-none-inline-main-light { display: inline !important; } [data-bs-main-theme="dark"] .d-none-main-dark, [data-bs-main-theme="dark"] .d-none-inline-main-dark { display: none !important; } .inline-menu li { display: inline-block; padding: 0.5rem; color: var(--bs-nav-link-color); } .inline-menu li .active, .inline-menu li>a:hover { box-shadow: inset 0 -1px 0 var(--bs-navbar-hover-color); } ul.inline-menu { padding: 0; } body.navbar-open { overflow: hidden; position: fixed; width: 100%; } ================================================ FILE: assets/scss/components/_pagination.scss ================================================ .pagination { --bs-pagination-bg: var(--bs-primary-bg-subtle); --bs-pagination-color: var(--bs-body-color); --bs-pagination-border-color: none; --bs-pagination-hover-color: var(--bs-pagination-active-color); --bs-pagination-hover-bg: var(--bs-pagination-active-bg); --bs-pagination-hover-border-color: none; .page-item { margin: 0.4rem; } .page-item:first-of-type { margin-left: 0; } } ================================================ FILE: assets/scss/components/_persona.scss ================================================ .persona { min-height: 320px !important } ================================================ FILE: assets/scss/components/_popover.scss ================================================ .popover-header { margin-top: 0; } ================================================ FILE: assets/scss/components/_sidebar.scss ================================================ // scss-docs-start sidebar .sidebar { top: var(--navbar-offset); } .sidebar-overflow { top: calc(var(--navbar-offset) + 1rem); max-height: calc(100vh - var(--navbar-offset)); overflow-y: auto; scrollbar-gutter: stable; } .sidebar-item { --bs-border-radius: #{$theme-border-radius}; --bs-border-radius-sm: #{$theme-border-radius}; --bs-border-radius-lg: #{$theme-border-radius}; --bs-border-radius-xl: #{$theme-border-radius}; --bs-border-radius-xxl: #{$theme-border-radius}; color: rgba(0, 0, 0, 0.65); margin-left: 0 !important; display: block; padding: 0.1875rem 0.5rem !important; &.active { color: $primary; } &:hover, &:focus { color: $primary; background-color: tint-color($primary, 90%); } } .sidebar-item-group { --#{$prefix}link-opacity: 0.65; border-radius: #{$theme-border-radius}; &:hover, &:focus { color: $primary; background-color: tint-color($primary, 90%); } > div > a { display: block; width: 100%; color: rgba(var(--#{$prefix}body-color-rgb), var(--#{$prefix}link-opacity, 1)); text-decoration: none; cursor: pointer; &:hover, &:focus { color: $primary; } } } .sidebar-item-group > div { padding: 0.1875rem 0 0.1875rem 0.5rem !important; } .btn-toggle-group { padding: 0.25rem 0.5rem; font-weight: 600; color: rgba(0, 0, 0, 0.65); background-color: transparent; &:hover, &:focus { background-color: transparent; } &::before { width: 1.25em; line-height: 0; content: $btn-toggle; transition: transform 0.35s ease; transform-origin: 0.5em 50%; } } .btn-toggle-group[aria-expanded="true"] { &::before { transform: rotate(90deg); } } @if $enable-dark-mode { @include color-mode(dark) { .sidebar-item { --#{$prefix}link-opacity: 0.65; color: rgba(var(--#{$prefix}body-color-rgb), var(--#{$prefix}link-opacity, 1)); &.active { color: $primary-text-emphasis-dark !important; } &:hover, &:focus { color: $primary-text-emphasis-dark !important; background-color: transparent; box-shadow: inset 0 0 0 1px $primary-bg-subtle-dark; } } .sidebar-item-group { color: var(--bs-body-color) !important; &.active { color: $primary-text-emphasis-dark !important; } &:hover, &:focus { color: $primary-text-emphasis-dark !important; background-color: transparent; box-shadow: inset 0 0 0 1px $primary-bg-subtle-dark; } > div > a { &:hover, &:focus { color: $primary-text-emphasis-dark !important; } } } .btn-toggle-group { color: var(--bs-body-color); &:hover, &:focus { background-color: transparent; } &::before { content: $btn-toggle-dark; } } .btn-toggle-group[aria-expanded="true"] { color: var(--bs-secondary-color); } } } // Collapsible sidebar .sidebar-no-transition, .sidebar-no-transition * { transition: none !important; } html.sidebar-pre-collapsed .sidebar-collapsible .sidebar-item-label { max-width: 0 !important; opacity: 0 !important; margin-inline-start: 0 !important; } .sidebar-toggle-btn { color: rgba(0, 0, 0, 0.65); &:hover { color: $primary; } .sidebar-icon-toggle { transition: transform 0.4s ease; } } .sidebar-item-label { display: inline-block; max-width: 200px; overflow: hidden; white-space: nowrap; vertical-align: middle; transition: max-width 0.2s ease, opacity 0.15s ease, margin-inline-start 0.2s ease; } .sidebar-collapsed { .sidebar-item-label { max-width: 0; opacity: 0; margin-inline-start: 0 !important; } .sidebar-toggle-btn .sidebar-icon-toggle { transform: rotate(180deg); } } @if $enable-dark-mode { @include color-mode(dark) { .sidebar-toggle-btn { color: var(--bs-body-color); &:hover { color: $primary-text-emphasis-dark; } } } } // Secondary group row: stack vertically (button above link) when sidebar is icon-only .sidebar-collapsed .sidebar-secondary-row, html.sidebar-pre-collapsed .sidebar-secondary-row { flex-direction: column-reverse; align-items: center; } // Secondary group — icon rotates down (180°) when collapsed, up (0°) when expanded .sidebar-secondary-icon { transition: transform 0.2s ease; transform: rotate(180deg); } .sidebar-secondary-toggle[aria-expanded="true"] .sidebar-secondary-icon { transform: rotate(0deg); } // Secondary group toggle button .sidebar-secondary-toggle { color: rgba(0, 0, 0, 0.65); padding: 0.1875rem 0.5rem; border-radius: #{$theme-border-radius}; &:hover, &:focus { color: $primary; background-color: tint-color($primary, 90%); } } @if $enable-dark-mode { @include color-mode(dark) { .sidebar-secondary-toggle { color: rgba(var(--#{$prefix}body-color-rgb), 0.65); &:hover, &:focus { color: $primary-text-emphasis-dark; background-color: transparent; box-shadow: inset 0 0 0 1px $primary-bg-subtle-dark; } } } } // Flex column sidebar so .sidebar-spacer pushes the secondary group to the bottom @include media-breakpoint-up(md) { .sidebar-has-spacer { display: flex; flex-direction: column; min-height: 100%; > ul.list-unstyled { flex: 1; display: flex; flex-direction: column; } } .sidebar-spacer { flex: 1 1 0; min-height: 1rem; } } // scss-docs-end sidebar .dropdown-toggle { outline: 0; display: flex; align-items: center; } ================================================ FILE: assets/scss/components/_syntax-dark.scss ================================================ /* Background */ .bg { color: #c9d1d9; background-color: #0d1117; } /* PreWrapper */ .chroma { color: #c9d1d9; background-color: #0d1117; } /* Other */ .chroma .x { } /* Error */ .chroma .err { color: #f85149 } /* CodeLine */ .chroma .cl { } /* LineLink */ .chroma .lnlinks { outline: none; text-decoration: none; color: inherit } /* 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: #373700 } /* LineNumbersTable */ .chroma .lnt { white-space: pre; -webkit-user-select: none; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #64686c } /* LineNumbers */ .chroma .ln { white-space: pre; -webkit-user-select: none; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #999fa8 } /* Line */ .chroma .line { display: flex; } /* Keyword */ .chroma .k { color: #ff7b72 } /* KeywordConstant */ .chroma .kc { color: #79c0ff } /* KeywordDeclaration */ .chroma .kd { color: #ff7b72 } /* KeywordNamespace */ .chroma .kn { color: #ff7b72 } /* KeywordPseudo */ .chroma .kp { color: #79c0ff } /* KeywordReserved */ .chroma .kr { color: #ff7b72 } /* KeywordType */ .chroma .kt { color: #ff7b72 } /* Name */ .chroma .n { } /* NameAttribute */ .chroma .na { color: #00cccc } /* NameBuiltin */ .chroma .nb { color: #00a2d8 } /* NameBuiltinPseudo */ .chroma .bp { } /* NameClass */ .chroma .nc { color: #f0883e; font-weight: bold } /* NameConstant */ .chroma .no { color: #79c0ff; font-weight: bold } /* NameDecorator */ .chroma .nd { color: #d2a8ff; font-weight: bold } /* NameEntity */ .chroma .ni { color: #ffa657 } /* NameException */ .chroma .ne { color: #f0883e; font-weight: bold } /* NameFunction */ .chroma .nf { color: #d2a8ff; font-weight: bold } /* NameFunctionMagic */ .chroma .fm { } /* NameLabel */ .chroma .nl { color: #79c0ff; font-weight: bold } /* NameNamespace */ .chroma .nn { color: #ff7b72 } /* NameOther */ .chroma .nx { } /* NameProperty */ .chroma .py { color: #79c0ff } /* NameTag */ .chroma .nt { color: #7ee787 } /* NameVariable */ .chroma .nv { color: #79c0ff } /* NameVariableClass */ .chroma .vc { } /* NameVariableGlobal */ .chroma .vg { } /* NameVariableInstance */ .chroma .vi { } /* NameVariableMagic */ .chroma .vm { } /* Literal */ .chroma .l { color: #a5d6ff } /* LiteralDate */ .chroma .ld { color: #79c0ff } /* LiteralString */ .chroma .s { color: #a5d6ff } /* LiteralStringAffix */ .chroma .sa { color: #79c0ff } /* LiteralStringBacktick */ .chroma .sb { color: #a5d6ff } /* LiteralStringChar */ .chroma .sc { color: #a5d6ff } /* LiteralStringDelimiter */ .chroma .dl { color: #79c0ff } /* LiteralStringDoc */ .chroma .sd { color: #a5d6ff } /* LiteralStringDouble */ .chroma .s2 { color: #a5d6ff } /* LiteralStringEscape */ .chroma .se { color: #79c0ff } /* LiteralStringHeredoc */ .chroma .sh { color: #79c0ff } /* LiteralStringInterpol */ .chroma .si { color: #a5d6ff } /* LiteralStringOther */ .chroma .sx { color: #a5d6ff } /* LiteralStringRegex */ .chroma .sr { color: #79c0ff } /* LiteralStringSingle */ .chroma .s1 { color: #a5d6ff } /* LiteralStringSymbol */ .chroma .ss { color: #a5d6ff } /* LiteralNumber */ .chroma .m { color: #a5d6ff } /* LiteralNumberBin */ .chroma .mb { color: #a5d6ff } /* LiteralNumberFloat */ .chroma .mf { color: #a5d6ff } /* LiteralNumberHex */ .chroma .mh { color: #a5d6ff } /* LiteralNumberInteger */ .chroma .mi { color: #a5d6ff } /* LiteralNumberIntegerLong */ .chroma .il { color: #a5d6ff } /* LiteralNumberOct */ .chroma .mo { color: #a5d6ff } /* Operator */ .chroma .o { color: #ff7b72; font-weight: bold } /* OperatorWord */ .chroma .ow { color: #ff7b72; font-weight: bold } /* Punctuation */ .chroma .p { } /* Comment */ .chroma .c { color: #979fa8; font-style: italic } /* CommentHashbang */ .chroma .ch { color: #979fa8; font-style: italic } /* CommentMultiline */ .chroma .cm { color: #979fa8; font-style: italic } /* CommentSingle */ .chroma .c1 { color: #979fa8; font-style: italic } /* CommentSpecial */ .chroma .cs { color: #979fa8; font-weight: bold; font-style: italic } /* CommentPreproc */ .chroma .cp { color: #979fa8; font-weight: bold; font-style: italic } /* CommentPreprocFile */ .chroma .cpf { color: #979fa8; font-weight: bold; font-style: italic } /* Generic */ .chroma .g { } /* GenericDeleted */ .chroma .gd { color: #ffa198; background-color: #490202 } /* GenericEmph */ .chroma .ge { font-style: italic } /* GenericError */ .chroma .gr { color: #ffa198 } /* GenericHeading */ .chroma .gh { color: #79c0ff; font-weight: bold } /* GenericInserted */ .chroma .gi { color: #56d364; background-color: #0f5323 } /* GenericOutput */ .chroma .go { color: #979fa8 } /* GenericPrompt */ .chroma .gp { color: #979fa8 } /* GenericStrong */ .chroma .gs { font-weight: bold } /* GenericSubheading */ .chroma .gu { color: #79c0ff } /* GenericTraceback */ .chroma .gt { color: #ff7b72 } /* GenericUnderline */ .chroma .gl { text-decoration: underline } /* TextWhitespace */ .chroma .w { color: #999fa8 } ================================================ FILE: assets/scss/components/_syntax-dart.scss ================================================ // stylelint-disable annotation-no-unknown @import "syntax-light"; .bg, .chroma, .chroma .err { // set to transparent background to avoid rendering issues with example shortcode background-color: transparent if($enable-important-utilities, !important, null); } .chroma { display: flex; } .chroma code { flex: 1; } .codeblock.syntax-highlight, .command.syntax-highlight { border-radius: #{$theme-border-radius}; } .syntax-highlight { background-color: var(--bs-light) if($enable-important-utilities, !important, null); overflow-x: auto; } @if $enable-dark-mode { [data-bs-theme="dark"] { @include meta.load-css(syntax-dark); .bg, .chroma, .chroma .err { // set to transparent background to avoid rendering issues with example shortcode background-color: transparent if($enable-important-utilities, !important, null); } .syntax-highlight { background-color: var(--bs-tertiary-bg) if($enable-important-utilities, !important, null); overflow-x: auto; } .bg, .chroma, .chroma .ge, .chroma .gl, .chroma .gs { color: #c9d1d9 if($enable-important-utilities, !important, null); } } } // stylelint-enable annotation-no-unknown ================================================ FILE: assets/scss/components/_syntax-light.scss ================================================ /* Background */ .bg { background-color: #ffffff; } /* PreWrapper */ .chroma { background-color: #ffffff; } /* Other */ .chroma .x { } /* Error */ .chroma .err { color: #a61717; background-color: #e3d2d2 } /* CodeLine */ .chroma .cl { } /* LineLink */ .chroma .lnlinks { outline: none; text-decoration: none; color: inherit } /* 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: #ffffcc } /* LineNumbersTable */ .chroma .lnt { white-space: pre; -webkit-user-select: none; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f } /* LineNumbers */ .chroma .ln { white-space: pre; -webkit-user-select: none; 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: #000000; font-weight: bold } /* KeywordConstant */ .chroma .kc { color: #000000; font-weight: bold } /* KeywordDeclaration */ .chroma .kd { color: #000000; font-weight: bold } /* KeywordNamespace */ .chroma .kn { color: #000000; font-weight: bold } /* KeywordPseudo */ .chroma .kp { color: #000000; font-weight: bold } /* KeywordReserved */ .chroma .kr { color: #000000; font-weight: bold } /* KeywordType */ .chroma .kt { color: #445588; font-weight: bold } /* Name */ .chroma .n { } /* NameAttribute */ .chroma .na { color: #008080 } /* NameBuiltin */ .chroma .nb { color: #006b8f } /* NameBuiltinPseudo */ .chroma .bp { color: #999999 } /* NameClass */ .chroma .nc { color: #445588; 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: #990000; font-weight: bold } /* NameFunction */ .chroma .nf { color: #990000; font-weight: bold } /* NameFunctionMagic */ .chroma .fm { } /* NameLabel */ .chroma .nl { color: #990000; font-weight: bold } /* NameNamespace */ .chroma .nn { color: #555555 } /* 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: #dd1144 } /* LiteralStringAffix */ .chroma .sa { color: #dd1144 } /* LiteralStringBacktick */ .chroma .sb { color: #dd1144 } /* LiteralStringChar */ .chroma .sc { color: #dd1144 } /* LiteralStringDelimiter */ .chroma .dl { color: #dd1144 } /* LiteralStringDoc */ .chroma .sd { color: #dd1144 } /* LiteralStringDouble */ .chroma .s2 { color: #dd1144 } /* LiteralStringEscape */ .chroma .se { color: #dd1144 } /* LiteralStringHeredoc */ .chroma .sh { color: #dd1144 } /* LiteralStringInterpol */ .chroma .si { color: #dd1144 } /* LiteralStringOther */ .chroma .sx { color: #dd1144 } /* LiteralStringRegex */ .chroma .sr { color: #009926 } /* LiteralStringSingle */ .chroma .s1 { color: #dd1144 } /* LiteralStringSymbol */ .chroma .ss { color: #990073 } /* LiteralNumber */ .chroma .m { color: #007a7a } /* LiteralNumberBin */ .chroma .mb { color: #007a7a } /* LiteralNumberFloat */ .chroma .mf { color: #007a7a } /* LiteralNumberHex */ .chroma .mh { color: #007a7a } /* LiteralNumberInteger */ .chroma .mi { color: #007a7a } /* LiteralNumberIntegerLong */ .chroma .il { color: #007a7a } /* LiteralNumberOct */ .chroma .mo { color: #007a7a } /* Operator */ .chroma .o { color: #000000; font-weight: bold } /* OperatorWord */ .chroma .ow { color: #000000; font-weight: bold } /* Punctuation */ .chroma .p { } /* Comment */ .chroma .c { color: #6d6d5d; font-style: italic } /* CommentHashbang */ .chroma .ch { color: #6d6d5d; font-style: italic } /* CommentMultiline */ .chroma .cm { color: #6d6d5d; font-style: italic } /* CommentSingle */ .chroma .c1 { color: #6d6d5d; font-style: italic } /* CommentSpecial */ .chroma .cs { color: #999999; font-weight: bold; font-style: italic } /* CommentPreproc */ .chroma .cp { color: #999999; font-weight: bold; font-style: italic } /* CommentPreprocFile */ .chroma .cpf { color: #999999; font-weight: bold; font-style: italic } /* Generic */ .chroma .g { } /* GenericDeleted */ .chroma .gd { color: #000000; background-color: #ffdddd } /* GenericEmph */ .chroma .ge { color: #000000; font-style: italic } /* GenericError */ .chroma .gr { color: #aa0000 } /* GenericHeading */ .chroma .gh { color: #999999 } /* GenericInserted */ .chroma .gi { color: #000000; background-color: #ddffdd } /* GenericOutput */ .chroma .go { color: #888888 } /* GenericPrompt */ .chroma .gp { color: #555555 } /* GenericStrong */ .chroma .gs { font-weight: bold } /* GenericSubheading */ .chroma .gu { color: #aaaaaa } /* GenericTraceback */ .chroma .gt { color: #aa0000 } /* GenericUnderline */ .chroma .gl { text-decoration: underline } /* TextWhitespace */ .chroma .w { color: #bbbbbb } ================================================ FILE: assets/scss/components/_syntax.scss ================================================ // stylelint-disable annotation-no-unknown @import "syntax-light"; .bg, .chroma, .chroma .err { // set to transparent background to avoid rendering issues with example shortcode background-color: transparent if($enable-important-utilities, !important, null); } .chroma { display: flex; } .chroma code { flex: 1; } .codeblock.syntax-highlight, .command.syntax-highlight { border-radius: #{$theme-border-radius}; } .syntax-highlight { background-color: var(--bs-light) if($enable-important-utilities, !important, null); overflow-x: auto; } @if $enable-dark-mode { [data-bs-theme="dark"] { @import "syntax-dark"; // stylelint-disable-line no-invalid-position-at-import-rule .bg, .chroma, .chroma .err { // set to transparent background to avoid rendering issues with example shortcode background-color: transparent if($enable-important-utilities, !important, null); } .syntax-highlight { background-color: var(--bs-tertiary-bg) if($enable-important-utilities, !important, null); overflow-x: auto; } .bg, .chroma, .chroma .ge, .chroma .gl, .chroma .gs { color: #c9d1d9 if($enable-important-utilities, !important, null); } } } // stylelint-enable annotation-no-unknown ================================================ FILE: assets/scss/components/_table.scss ================================================ .datatable-container { border-bottom: none if($enable-important-utilities, !important, null); } .datatable-bottom { padding-top: 0 if($enable-important-utilities, !important, null); } .datatable-sorter { padding-left: 0; padding-right: 1rem; } .table-border-bottom-wrap { border-bottom-style: none !important } @if $enable-dark-mode { @include color-mode(dark) { .table-striped, .table-striped-columns { --bs-table-striped-bg: var(--bs-tertiary-bg); --bs-table-striped-color: var(--bs-body-color); } .table-hover { --bs-table-hover-bg: var(--bs-tertiary-bg); --bs-table-striped-color: var(--bs-body-color); } .datatable-pagination-list-item { &:hover, &:focus, &.datatable-active { color: var(--bs-body-bg) !important; } } } } ================================================ FILE: assets/scss/components/_testimonial.scss ================================================ .testimonial-img { height: 10vw; width: 10vw; background-color: var(--#{$prefix}body-bg); } .testimonial-logo { width: 20vw; } @include media-breakpoint-up(md) { .testimonial-img { height: 5vw; width: 5vw; } .testimonial-logo { width: 10vw; } } ================================================ FILE: assets/scss/components/_timeline.scss ================================================ // scss-docs-start timeline $connector-radius: 0.8rem; $semi-circle-radius: 8rem; $semi-circle-border: 0.2rem; :root { --timeline-highlight: var(--bs-primary); --timeline-icon-radius: #{$semi-circle-radius}; --timeline-offset: 50%; --timeline-connector-bg: var(--bs-body-bg); } @each $state in map-keys($theme-colors) { .timeline-#{$state} { --timeline-highlight: var(--#{$prefix}#{$state}); } .timeline-bg-#{$state} { --timeline-connector-bg: var(--#{$prefix}#{$state}); } .timeline-bg-#{$state}-subtle { --timeline-connector-bg: var(--#{$prefix}#{$state}-bg-subtle); } } // scss-docs-end timeline .timeline-container { border-radius: #{$theme-border-radius}; } .timeline, .timeline-sm { position: relative; } .timeline-sm { --timeline-icon-radius: calc(#{$semi-circle-radius} / 2.4); --timeline-offset: 25% } @include media-breakpoint-up(sm) { .timeline-sm { --timeline-icon-radius: calc(#{$semi-circle-radius} / 2); } } .timeline::before, .timeline-sm::before { content: ""; width: 2 * $semi-circle-border; margin: 0 auto; background: var(--bs-body-color); position: absolute; inset: 0; } .timeline-sm::before { margin: 0 calc(var(--timeline-offset) - #{$semi-circle-border}); } .timeline-semi-circle-start, .timeline-semi-circle-end { width: var(--timeline-icon-radius); height: var(--timeline-icon-radius); border-radius: 100%; position: relative; } .timeline-semi-circle-start { left: -$semi-circle-border; } .timeline-semi-circle-end { left: $semi-circle-border; } .timeline-semi-circle-start::before { content: ""; width: var(--timeline-icon-radius); height: var(--timeline-icon-radius); border-radius: 100%; border: $semi-circle-border solid; position: absolute; border-color: transparent var(--timeline-highlight) var(--timeline-highlight) var(--timeline-highlight); transform: rotate(-90deg); } .timeline-semi-circle-start::after { content: ""; left: 0; top: 0; width: var(--timeline-icon-radius); height: var(--timeline-icon-radius); border-radius: 100%; border: $semi-circle-border solid; position: absolute; border-color: var(--timeline-highlight) var(--timeline-highlight) var(--timeline-highlight) transparent; transform: rotate(-45deg); } .timeline-semi-circle-end::before { content: ""; width: var(--timeline-icon-radius); height: var(--timeline-icon-radius); border-radius: 100%; border: $semi-circle-border solid; position: absolute; border-color: transparent var(--timeline-highlight) var(--timeline-highlight) var(--timeline-highlight); transform: rotate(-225deg); } .timeline-semi-circle-end::after { content: ""; left: 0; top: 0; width: var(--timeline-icon-radius); height: var(--timeline-icon-radius); border-radius: 100%; border: $semi-circle-border solid; position: absolute; border-color: var(--timeline-highlight) var(--timeline-highlight) var(--timeline-highlight) transparent; transform: rotate(-180deg); } .timeline-description-text-start { border-bottom: $semi-circle-border solid var(--timeline-highlight); margin-right: 2 * $connector-radius; } .timeline-description-text-end { border-bottom: $semi-circle-border solid var(--timeline-highlight); margin-left: 2 * $connector-radius; } .timeline-panel-start, .timeline-panel-end, .timeline-connector-start, .timeline-connector-end { top: calc(var(--timeline-icon-radius) / 2); position: relative; width: calc(var(--timeline-icon-radius) / 2); height: calc($semi-circle-border + var(--timeline-icon-radius) / 2); border: $semi-circle-border solid var(--timeline-highlight); border-bottom: none; border-right: none; border-left: none; } .timeline-panel-start { top: 50%; right: 50%; position: absolute; width: calc(var(--timeline-icon-radius) * 2); width: 2 * $connector-radius; height: 50%; border-top: $semi-circle-border solid var(--timeline-highlight); border-left: $semi-circle-border solid var(--timeline-highlight); } .timeline-panel-end { top: 50%; position: absolute; width: calc(var(--timeline-icon-radius) * 2); width: 2 * $connector-radius; height: 50%; border-top: $semi-circle-border solid var(--timeline-highlight); border-right: $semi-circle-border solid var(--timeline-highlight); } .timeline-dot::after { display: inline-block; content: ""; position: absolute; top: 50%; left: var(--timeline-offset); margin: (-$connector-radius) 0 0 (-$connector-radius); width: 2 * $connector-radius; height: 2 * $connector-radius; border-radius: 100%; border: ($semi-circle-border * 1.5) solid var(--timeline-connector-bg); color: var(--timeline-highlight); background: var(--timeline-highlight); } // Compact start-aligned timeline (layout="start") .timeline-start { list-style: none; padding-inline-start: 1rem; margin: 0; position: relative; &::before { content: ""; position: absolute; inset-inline-start: 0; top: 0.4rem; bottom: 0.4rem; width: $semi-circle-border; background: var(--bs-border-color); } li { position: relative; padding-inline-start: 1rem; margin-bottom: 0.75rem; &:last-child { margin-bottom: 0; } &::before { content: ""; position: absolute; inset-inline-start: calc(#{$semi-circle-border} / 2 - 1.2rem); top: 0.4rem; width: 0.4rem; height: 0.4rem; border-radius: 100%; background: var(--bs-primary); } } } ================================================ FILE: assets/scss/components/_toast.scss ================================================ .toast { border-radius: #{$theme-border-radius}; overflow: hidden; } ================================================ FILE: assets/scss/components/_toc.scss ================================================ // // Table of contents sidebar & drop-down panel // // scss-docs-start toc .toc-sidebar { top: calc(var(--navbar-offset) + 1rem); max-height: calc(100vh - var(--navbar-offset)); overflow-y: auto; right: 0; z-index: 2; } // scss-docs-end toc .toc nav { font-size: 0.875rem; margin-bottom: -0.875rem; } .toc nav ul { padding-left: 0; list-style: none; } .toc nav ul ul { padding-left: 1rem; margin-top: 0.25rem; } .toc nav li { margin-bottom: 0.25rem; } .toc nav a { color: inherit; &:hover { color: var(--bs-primary); } } .toc nav a:not(:hover) { text-decoration: none; } .toc nav a code { font: inherit; } #toc-collapse { border-color: var(--bs-secondary-color) !important; border-radius: 0 0 var(--bs-border-radius) var(--bs-border-radius) !important; margin-top: -1.5rem; padding-top: 1.5rem !important; } .toc-button { --bs-btn-hover-color: var(--bs-primary); --bs-btn-hover-bg: var(--bs-body-bg); --bs-btn-hover-border-color: var(--bs-primary); --bs-btn-active-color: var(--bs-primary); --bs-btn-active-bg: var(--bs-body-bg); --bs-btn-active-border-color: var(--bs-primary); background-color: var(--#{$prefix}body-bg) !important; &.active, &:hover, &:focus { color: var(--bs-primary); border-color: var(--bs-primary); box-shadow: 0 0 0 4px var(--bs-primary-border-subtle); outline: none; } } .btn-link.toc-item { font-size: inherit; } #btnTOCShowMore { padding-top: 0.875rem; } a.toc-item { display: block; } a.toc-level-1 { margin-left: 0; } a.toc-level-2 { margin-left: 1em; } a.toc-level-3 { margin-left: 2em; } a.toc-level-4 { margin-left: 3em; } a.toc-level-5 { margin-left: 4em; } a.toc-level-6 { margin-left: 5em; } @if $enable-dark-mode { [data-bs-theme="dark"] { .toc-button { --bs-btn-color: var(--bs-body-color); --bs-btn-border-color: var(--bs-body-color); &:hover { background-color: transparent; } } #toc-collapse { border-color: var(--bs-body-color) !important; } .toc nav a { color: var(--bs-body-color); &:hover { color: white; } } } } .section-menu > .nav-link.active, .section-menu > .nav-link:hover { color: var(--bs-primary); } ================================================ FILE: assets/scss/components/_tooltip.scss ================================================ .btn-tooltip a { text-decoration: none; } .btn-tooltip a[href] { color: var(--bs-link-color) !important; text-decoration-color: var(--bs-link-color) !important; } ================================================ FILE: assets/scss/components/_video.scss ================================================ .video-embedded { position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; border-radius: #{$theme-border-radius}; } .video-embedded > iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; } // Adapted from https://github.com/gohugoio/hugo/tpl/tplimpl/embedded/templates/shortcodes/vimeo_simple.html .__h_video { position: relative; padding-bottom: 56.23%; height: 0; overflow: hidden; width: 100%; background: #000; } .__h_video img { width: 100%; height: auto; color: #000; } .__h_video .play { height: 72px; width: 72px; left: 50%; top: 50%; margin-left: -36px; margin-top: -36px; position: absolute; cursor: pointer; } .video { position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; } .video iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; } ================================================ FILE: assets/scss/helpers/_colored-links.scss ================================================ // scss-docs-start colored-links $custom-colors: ( "primary": "light", "secondary": "light", "success": "light", "danger": "light", "dark": "light", "black": "light", "info": "dark", "warning": "dark", "light": "dark", "white": "dark", "body": "adaptive", "body-tertiary": "adaptive" ); @each $color, $value in $custom-colors { $main-color: var(--bs-body-color); $emphasize-color: var(--bs-secondary-color); @if $value == "light" { $main-color: $white; $emphasize-color: shade-color($main-color, $link-shade-percentage); } @else if $value == "dark" { $main-color: $black; $emphasize-color: tint-color($main-color, $link-shade-percentage); } .link-bg-#{$color} { color: $main-color if($enable-important-utilities, !important, null); &:hover, &:focus { color: $emphasize-color if($enable-important-utilities, !important, null); } } } // scss-docs-end colored-links ================================================ FILE: assets/scss/helpers/_display.scss ================================================ .hidden { display: none; } // stylelint-disable annotation-no-unknown // scss-docs-start display-color .d-none-light, .d-none-inline-light { display: none if($enable-important-utilities, !important, null); } .d-none-dark { display: block if($enable-important-utilities, !important, null); } .d-none-inline-dark { display: inline if($enable-important-utilities, !important, null); } @if $enable-dark-mode { @include color-mode(dark) { .d-none-light { display: block if($enable-important-utilities, !important, null); } .d-none-inline-light { display: inline if($enable-important-utilities, !important, null); } .d-none-dark, .d-none-inline-dark { display: none if($enable-important-utilities, !important, null); } } } // scss-docs-end display-color // stylelint-enable annotation-no-unknown ================================================ FILE: assets/scss/layouts/_reboot.scss ================================================ pre { padding: $spacer; margin-bottom: 0; } ================================================ FILE: assets/scss/layouts/_type.scss ================================================ // // Headings // h1 { margin-top: $spacer * 2.5; scroll-margin-top: var(--navbar-offset); } h2 { margin-top: $spacer * 2; scroll-margin-top: var(--navbar-offset); } h3 { margin-top: $spacer * 1.75; scroll-margin-top: var(--navbar-offset); } h4 { margin-top: $spacer * 1.5; scroll-margin-top: var(--navbar-offset); } h5 { margin-top: $spacer * 1.25; scroll-margin-top: var(--navbar-offset); } h6 { margin-top: $spacer; scroll-margin-top: var(--navbar-offset); } .display-1, .display-2, .display-3, .display-4, .display-5, .display-6 { scroll-margin-top: var(--navbar-offset); } ================================================ FILE: assets/scss/theme/_variables.scss ================================================ // Placeholder to quickly add your own theme variable overrides // The file is included at the beginning of the build pipeline ================================================ FILE: assets/scss/theme/base.scss ================================================ // Placeholder for themes extending the core Hinode theme // The file is included last in the build pipeline, but prior to theme.scss ================================================ FILE: assets/scss/theme/fonts.scss ================================================ /*! * Copyright (c) 2016-2020 The Inter Project Authors. * "Inter" is trademark of Rasmus Andersson. * https://github.com/rsms/inter * This Font Software is licensed under the SIL Open Font License, Version 1.1. * This license is copied below, and is also available with a FAQ at: * http://scripts.sil.org/OFL */ /* inter-200 - latin */ @font-face { font-display: block; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ font-family: 'Inter'; font-style: normal; font-weight: 200; src: url('../fonts/inter-v12-latin-200.eot'); /* IE9 Compat Modes */ src: url('../fonts/inter-v12-latin-200.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('../fonts/inter-v12-latin-200.woff2') format('woff2'), /* Super Modern Browsers */ url('../fonts/inter-v12-latin-200.woff') format('woff'), /* Modern Browsers */ url('../fonts/inter-v12-latin-200.ttf') format('truetype'), /* Safari, Android, iOS */ url('../fonts/inter-v12-latin-200.svg#Inter') format('svg'); /* Legacy iOS */ } /* inter-300 - latin */ @font-face { font-display: block; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ font-family: 'Inter'; font-style: normal; font-weight: 300; src: url('../fonts/inter-v12-latin-300.eot'); /* IE9 Compat Modes */ src: url('../fonts/inter-v12-latin-300.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('../fonts/inter-v12-latin-300.woff2') format('woff2'), /* Super Modern Browsers */ url('../fonts/inter-v12-latin-300.woff') format('woff'), /* Modern Browsers */ url('../fonts/inter-v12-latin-300.ttf') format('truetype'), /* Safari, Android, iOS */ url('../fonts/inter-v12-latin-300.svg#Inter') format('svg'); /* Legacy iOS */ } /* inter-regular - latin */ @font-face { font-display: block; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ font-family: 'Inter'; font-style: normal; font-weight: 400; src: url('../fonts/inter-v12-latin-regular.eot'); /* IE9 Compat Modes */ src: url('../fonts/inter-v12-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('../fonts/inter-v12-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ url('../fonts/inter-v12-latin-regular.woff') format('woff'), /* Modern Browsers */ url('../fonts/inter-v12-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ url('../fonts/inter-v12-latin-regular.svg#Inter') format('svg'); /* Legacy iOS */ } /* inter-600 - latin */ @font-face { font-display: block; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ font-family: 'Inter'; font-style: normal; font-weight: 600; src: url('../fonts/inter-v12-latin-600.eot'); /* IE9 Compat Modes */ src: url('../fonts/inter-v12-latin-600.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('../fonts/inter-v12-latin-600.woff2') format('woff2'), /* Super Modern Browsers */ url('../fonts/inter-v12-latin-600.woff') format('woff'), /* Modern Browsers */ url('../fonts/inter-v12-latin-600.ttf') format('truetype'), /* Safari, Android, iOS */ url('../fonts/inter-v12-latin-600.svg#Inter') format('svg'); /* Legacy iOS */ } ================================================ FILE: assets/scss/theme/theme.scss ================================================ // Placeholder to quickly add your own styles // The file is included last in the build pipeline ================================================ FILE: assets/scss/vendor/.gitkeep ================================================ ================================================ FILE: commitlint.config.js ================================================ module.exports = {extends: ['@commitlint/config-conventional']} ================================================ FILE: config/_default/hugo.toml ================================================ # toml-docs-start main title = "Hinode" copyright = "Copyright © 2026 Hinode Team" enableGitInfo = true # toml-docs-end main # additional settings baseURL = "https://example.com/" canonifyURLs = false enableEmoji = true enableRobotsTXT = true enableInlineShortcodes = true summaryLength = 20 # prevent build failures when using Hugo's Instagram shortcode due to deprecated Instagram API. # See https://github.com/gohugoio/hugo/issues/7228#issuecomment-714490456 ignoreErrors = ["error-remote-getjson"] # toml-docs-start timeout timeout = "180s" # toml-docs-end timeout # toml-docs-start language languageCode = "en-us" defaultContentLanguage = "en" defaultContentLanguageInSubdir = false # toml-docs-end language # toml-docs-start headers [outputFormats] [outputFormats.server] mediaType = "application/toml" baseName = "server" isPlainText = true notAlternative = true permalinkable = true root = true [outputFormats.netlify] mediaType = "application/toml" baseName = "netlify" isPlainText = true notAlternative = true permalinkable = true root = true # toml-docs-end headers [outputFormats.XML] isPlainText = false mediaType = "application/xml" isHtml = false noUgly = true permalinkable = false name = "xml" # toml-docs-start redirect [outputFormats.REDIR] mediaType = "text/netlify" baseName = "_redirects" isPlainText = true notAlternative = true [mediaTypes."text/netlify"] delimiter = "" # toml-docs-end redirect # toml-docs-start outputs [outputs] home = ["HTML", "RSS", "REDIR", "netlify", "server"] # toml-docs-end outputs # toml-docs-start build [build] writeStats = true # toml-docs-end build [taxonomies] tag = 'tags' [pagination] pagerSize = 9 [privacy] [privacy.vimeo] disabled = false simple = true [privacy.x] disabled = false enableDNT = true simple = true [privacy.instagram] disabled = false simple = true [privacy.youtube] disabled = false privacyEnhanced = true [services] [services.instagram] disableInlineCSS = true [services.x] disableInlineCSS = true [services.googleAnalytics] # ID = "G-xxxxxxxxxx" [minify] [minify.tdewolff.js] keepVarNames = true precision = 0 version = 2022 [minify.tdewolff.html] keepWhitespace = true [module] [module.hugoVersion] extended = true min = "0.146.0" [[module.mounts]] source = "archetypes" target = "archetypes" [[module.mounts]] source = "assets" target = "assets" [[module.mounts]] source = "content" target = "content" [[module.mounts]] source = "data" target = "data" [[module.mounts]] source = "i18n" target = "i18n" [[module.mounts]] source = "layouts" target = "layouts" [[module.mounts]] source = "static" target = "static" [[module.mounts]] source = "netlify.toml" target = "assets/config/netlify.toml" # toml-docs-start modules [[module.imports]] path = "github.com/gethinode/mod-bootstrap" [[module.imports]] path = "github.com/gethinode/mod-csp" [[module.imports]] path = "github.com/gethinode/mod-flexsearch/v4" [[module.imports]] path = "github.com/gethinode/mod-fontawesome/v5" [[module.imports]] path = "github.com/gethinode/mod-google-analytics/v2" [[module.imports]] path = "github.com/gethinode/mod-katex" [[module.imports]] path = "github.com/gethinode/mod-leaflet/v2" [[module.imports]] path = "github.com/gethinode/mod-lottie/v2" [[module.imports]] path = "github.com/gethinode/mod-mermaid/v4" [[module.imports]] path = "github.com/gethinode/mod-simple-datatables/v3" [[module.imports]] path = "github.com/gethinode/mod-utils/v5" # toml-docs-end modules # toml-docs-start segments [segments] [segments.headers] [[segments.headers.includes]] kind = '{home}' output = '{netlify,server}' # toml-docs-end segments ================================================ FILE: config/_default/languages.toml ================================================ # toml-docs-start lang-main [en] languageName = "English" contentDir = "content" weight = 1 # toml-docs-end lang-main # toml-docs-start lang-param [en.params.head] tagline = "A Hugo Theme" [en.params.social] title = "Follow me" caption = "I work on everything coding and tweet developer memes" [en.params.footer] # license = "Licensed under Creative Commons (CC BY-NC-SA 4.0)." # toml-docs-end lang-param ================================================ FILE: config/_default/markup.toml ================================================ defaultMarkdownHandler = "goldmark" [highlight] anchorLineNos = false codeFences = true guessSyntax = true hl_Lines = "" lineAnchors = "" lineNoStart = 1 lineNos = false lineNumbersInTable = false noClasses = false tabWidth = 2 ## Update the 'create:syntax' command in package.json to modify the style ## The first two lines have been modified to remove the background color # style = "monokailight" [goldmark] [goldmark.extensions] definitionList = true footnote = true linkify = true strikethrough = true table = true taskList = true typographer = true [goldmark.extensions.passthrough] enable = true [goldmark.extensions.passthrough.delimiters] block = [['\[', '\]'], ['$$', '$$']] inline = [['\(', '\)'], ['$', '$']] [goldmark.parser] autoHeadingID = true autoHeadingIDType = 'github' wrapStandAloneImageWithinParagraph = false [goldmark.parser.attribute] block = true [goldmark.renderer] hardWraps = false unsafe = false xhtml = false ================================================ FILE: config/_default/menus/menus.en.toml ================================================ [[main]] name = "Home" pageRef = "/" weight = 10 [[main]] name = "Tags" pageRef = "/tags" weight = 20 [[social]] name = "LinkedIn" pre = "fab linkedin" url = "https://linkedin.com/" weight = 10 [[social]] name = "GitHub" pre = "fab fa-github" url = "https://github.com/" weight = 20 [[social]] name = "Medium" pre = "fab medium" url = "https://medium.com/" weight = 30 ================================================ FILE: config/_default/params.toml ================================================ # toml-docs-start main [main] separator = "-" description = "Hinode is a clean documentation and blog theme for your Hugo site based on Bootstrap 5." enableLanguageSelectionStorage = false canonifyAssetsURLs = false endorse = true footerBelowFold = false loading = "lazy" breakpoint = "md" titleCase = false [main.padding] x = 4 y = 4 [main.internalLinks] validate = true pretty = false [main.externalLinks] cue = false tab = false [main.build] transpiler = "dartsass" silenceDeprecations = true [main.colorMode] enabled = true modes = ["light", "dark"] toggle = false [main.cards] linkIcon = false # toml-docs-end main # toml-docs-start icons [icons] # Color mode toggle colorModeLight = "fas sun" colorModeDark = "fas moon" # Navbar navbarLanguage = "fas globe" navbarOverflow = "fas ellipsis" navbarVersionCheck = "fas check" # Pagination paginationFirst = "fas angles-left" paginationPrev = "fas angle-left" paginationNext = "fas angle-right" paginationLast = "fas angles-right" # Other navigation breadcrumbBack = "fas angle-left" pageNavPrev = "fas arrow-left" pageNavNext = "fas arrow-right" # Content tocSort = "fas sort" cardReadMore = "fas chevron-right" cardLinkIcon = "fas arrow-right" externalLink = "fas up-right-from-square" testimonialNext = "fas chevron-right" testimonialQuote = "fas quote-right" headingAnchor = "fas link" notFoundPage = "fas link-slash" sharingWebshare = "fas share-nodes" sharingDownload = "fas download" # Sidebar sidebarCollapse = "fas angles-left" sidebarSecondary = "fas angle-down" # Form formSubmitButton = "fa paper-plane" formSubmittedIcon = "fa envelope" [icons.admonition] note = "fas circle-info" info = "fas circle-info" tip = "fa lightbulb" important = "fas exclamation" warning = "fas triangle-exclamation" caution = "fa hand" [icons.release] deprecated = "fas trash-can" feature = "fas rocket" # toml-docs-end icons # toml-docs-start images [images] [images.cloudinary] host = "cloudinary" [images.imagekit] host = "imagekit" [images.imgix] host = "imgix" # toml-docs-end images # toml-docs-start videos [videos] [videos.cloudinary] host = "cloudinary" account = "demo" [videos.vimeo] host = "vimeo" [videos.youtube] host = "youtube" # toml-docs-end videos [dam] videoCodecs = [ "webm/vp9", "mp4/h265", "mp4" ] # toml-docs-start debugging [debugging] showJS = false showSCSS = false purgeHTMLComments = false includeSVGOrigin = true # toml-docs-end debugging # toml-docs-start docs [docs] github = "https://github.com/gethinode/hinode" release = "https://github.com/gethinode/hinode/releases/tag/" checkVersion = false # toml-docs-end docs # toml-docs-start home [home] # sections = ["posts"] fullCover = false centerHeadline = false style = "" [home.feature] orientation = "horizontal" color = "primary" width = 4 align = "start" # toml-docs-end home # toml-docs-start navigation [navigation] anchor = true logo = "/img/logo_icon.svg" logo-mode = false logo-align = "center" logo-height = 30 color = "body" fixed = true overlay = false overlayMode = "dark" horizontal = false offset = "5.7rem" breadcrumb = true toc = true sidebar = true size = "md" startLevel = 2 endLevel = 3 maxNumHeadings = 9 [navigation.padding] x = 4 y = 4 [navigation.search] enabled = true modal = true # toml-docs-end navigation # toml-docs-start messages [messages] placement = "bottom-right" # toml-docs-end messages [pages] readingTime = true wordCount = true # toml-docs-start sharing [sharing] enabled = true sort = "weight" reverse = false webshare = true [[sharing.providers]] name = "LinkedIn" url = "https://www.linkedin.com/sharing/share-offsite/?url={url}" icon = "fab linkedin" weight = 10 [[sharing.providers]] name = "Twitter" url = "https://twitter.com/home?status={url}" icon = "fab x-twitter" weight = 20 [[sharing.providers]] name = "Facebook" url = "https://www.facebook.com/sharer.php?u={url}" icon = "fab facebook" weight = 30 [[sharing.providers]] name = "WhatsApp" url = "whatsapp://send?text={title}%20{url}" icon = "fab whatsapp" weight = 40 [[sharing.providers]] name = "email" url = "{url}" icon = "fas link" weight = 50 clipboard = true # toml-docs-end sharing [favicon] logo = "img/favicon.png" sizes = [16, 32, 48] # toml-docs-start theme-colors [style] primary = "#d43900" secondary = "#6c757d" success = "#198754" info = "#0dcaf0" warning = "#ffc107" danger = "#dc3545" light = "#f8f9fa" dark = "#212529" # toml-docs-end theme-colors themeOpacity = "10" darkModeShade = "20%" darkModeTint = "40%" # toml-docs-start font themeFont = "Inter" # themeFontPath = "https://fonts.googleapis.com/css2?family=Inter:wght@200;300;600&display=swap" # external path themeFontPath = "/fonts" # local path themeFontPreload = "/fonts/inter-v12-latin-regular.woff2" fontSizeBase = "1rem" # assumes the browser default, typically '16px' # toml-docs-end font # toml-docs-start build purge = false # toml-docs-end build [style.title] size = 4 arrangement = "above" headingStyle = "display" contentStyle = "lead text-muted" [schema] type = "Organization" name = "Hinode" locale = "en-US" # twitter = "https://twitter.com/gethinode" # linkedIn = "" github = "https://github.com/gethinode/hinode" section = "blog" [schema.author] name = "Mark Dumay" # twitter = "https://twitter.com/markdumay" linkedin = "https://www.linkedin.com/in/markdumay/" github = "https://github.com/markdumay" [schema.logo] url = "img/logo512x512.png" width = 512 height = 512 [schema.image] url = "img/logo1280x640.png" width = 1280 height = 640 [opengraph] images = ["logo.png"] locale = "en_US" [links] hinode = "https://gethinode.com" # toml-docs-start headers [headers] [headers.netlify] source = "netlify.toml" # toml-docs-end headers # toml-docs-start csp [modules.hinode.csp] style-src = ["www.youtube.com"] font-src = ["fonts.gstatic.com"] frame-src = [ "player.cloudinary.com", "www.youtube-nocookie.com", "www.youtube.com" ] img-src = [ "data:", "*.imgix.net", "*.imagekit.io", "*.cloudinary.com", "i.ytimg.com" ] # toml-docs-end csp [modules.vimeo] local = true integration = "optional" state = "async" url = "https://player.vimeo.com/api/player.js" [modules.vimeo.csp] frame-src = ["player.vimeo.com"] img-src = ["i.vimeocdn.com"] script-src = ["player.vimeo.com"] ================================================ FILE: config/_default/server.toml ================================================ # Auto-generated file - do not modify [[headers]] for = '/**' [headers.values] Access-Control-Allow-Origin = '*' Content-Security-Policy = """ base-uri 'self'; \ connect-src 'self' *.analytics.google.com *.google.com *.google-analytics.com *.googletagmanager.com; \ default-src 'none'; \ font-src 'self' fonts.gstatic.com data:; \ form-action 'self'; \ frame-ancestors 'self' http://localhost:1313 gethinode.com; \ frame-src *.googletagmanager.com player.cloudinary.com www.youtube-nocookie.com www.youtube.com player.vimeo.com; \ img-src 'self' *.google-analytics.com *.googletagmanager.com googletagmanager.com ssl.gstatic.com www.gstatic.com data: *.imgix.net *.imagekit.io *.cloudinary.com i.ytimg.com tile.openstreetmap.org i.vimeocdn.com; \ manifest-src 'self'; \ media-src 'self'; \ object-src 'none'; \ script-src 'self' *.google-analytics.com *.googletagmanager.com *.analytics.google.com googletagmanager.com tagmanager.google.com player.vimeo.com; \ style-src 'self' googletagmanager.com tagmanager.google.com fonts.googleapis.com www.youtube.com 'unsafe-inline'; \ """ Permissions-Policy = 'geolocation=(), midi=(), sync-xhr=(), microphone=(), camera=(), magnetometer=(), gyroscope=(), fullscreen=(), payment=() ' Referrer-Policy = 'strict-origin' Strict-Transport-Security = 'max-age=31536000; includeSubDomains; preload' X-Content-Type-Options = 'nosniff' X-XSS-Protection = '1; mode=block' cache-control = 'max-age=0, no-cache, no-store, must-revalidate ' ================================================ FILE: config/ci/hugo.toml ================================================ # cachedir default on POSIX: '/tmp/hugo_cache_runner' # cachedir default on Windows: '~\AppData\Local\hugo_cache' # cachedir default on macOS: '/Users/runner/Library/Caches/hugo_cache' # # All six Hugo cache types are configured here to: # - redirect assets/images from :resourceDir to :cacheDir so GitHub Actions can cache them # - set maxAge = -1 across the board so --gc never prunes entries between CI runs [caches] [caches.assets] dir = ':cacheDir/resources/_gen' # redirect from :resourceDir to :cacheDir maxAge = -1 [caches.getresource] dir = ':cacheDir/:project' maxAge = -1 [caches.images] dir = ':cacheDir/resources/_gen' # redirect from :resourceDir to :cacheDir maxAge = -1 [caches.misc] dir = ':cacheDir/:project' maxAge = -1 [caches.modulequeries] dir = ':cacheDir/modules' maxAge = -1 # override default 24h so --gc does not prune module query results [caches.modules] dir = ':cacheDir/modules' maxAge = -1 ================================================ FILE: config/development/params.toml ================================================ # Development-specific parameters for Hinode theme [modules.hinode.csp] frame-ancestors = [ "'self'", "http://localhost:1313", # Allow self-embedding for testing "gethinode.com" # Production embedding ] frame-src = [ "*.googletagmanager.com", "player.cloudinary.com", "www.youtube-nocookie.com", "www.youtube.com", "player.vimeo.com" ] ================================================ FILE: config/postcss.config.js ================================================ const autoprefixer = require('autoprefixer')({}) const cssnano = require('cssnano')({ preset: ['advanced', { discardUnused: { fontFace: false // Preserve all @font-face declarations } }] }) const purgeImport = require('@fullhuman/postcss-purgecss') const purgeCSSPlugin = purgeImport.purgeCSSPlugin || purgeImport.default || purgeImport const purgecss = purgeCSSPlugin({ content: ['./hugo_stats.json'], defaultExtractor: (content) => { const els = JSON.parse(content).htmlElements return [...(els.tags || []), ...(els.classes || []), ...(els.ids || [])] }, dynamicAttributes: ['aria-expanded', 'data-bs-theme', 'data-bs-main-theme', 'data-bs-theme-animate', 'data-transparent', 'role'], fontFace: false, safelist: { standard: [ // Bootstrap form validation 'was-validated', // Bootstrap dynamic states 'show', 'showing', 'hiding', 'active', 'disabled', 'collapsed', 'collapsing', // SimpleDatatables modifier classes 'no-header', 'no-footer', // SimpleDatatables table rendering classes (added by JS) 'th-inner', 'sortable', 'sortable-center', 'both', 'desc', 'asc', // SimpleDatatables search component 'search-data-table', 'search-input', // Bootstrap utilities used by SimpleDatatables 'float-right', 'float-left' ], // Classes with these patterns will be preserved along with their children deep: [ // Bootstrap components that get dynamically modified /modal/, /dropdown/, /carousel/, /tooltip/, /popover/, /collapse/, /offcanvas/, // SimpleDatatables - preserve structure and all nested elements /datatable/, // Bootstrap form controls (used by SimpleDatatables) /form-select/, /form-control/, // Bootstrap button groups (used by SimpleDatatables search) /btn-group/, // Bootstrap responsive tables (used by list component) /table-responsive/, // Syntax highlighting - preserve Chroma classes and descendants /chroma/, /syntax-highlight/, /codeblock/ ], // Preserve any selector containing these patterns greedy: [ // Third-party library prefixes (well-namespaced, safe to use greedy) /^fa-/, // FontAwesome /^leaflet-/, // Leaflet maps /^katex-/, // KaTeX math (note: using katex- not just katex) /^mermaid/, // Mermaid diagrams /datatable/, // SimpleDatatables (all variants: datatable-*, *-datatable, etc.) /^cky-/, // CookieYes // Component-specific prefixes /clipboard-/, // Clipboard component /command-/, // Command component /search-/, // Search functionality (includes search-input, search-data-table) /suggestion__/, // Search suggestions (FlexSearch) /testimonial-/, // Testimonial component /preview-/, // Preview component (mod-blocks) // Syntax highlighting - third-party engines (Chroma handled in deep) /^hljs-/, // highlight.js /^language-/, // Prism/generic // Pagination and navigation /page-item/, /page-link/, /pagination/, // Bootstrap pagination classes /nav-item/, /nav-link/, /navbar-/, /^nav-/, // Nav variant classes (nav-callout, nav-panel, nav-pills, nav-tabs, nav-underline) // Bootstrap responsive tables /table-responsive/, // All table-responsive-* variants and attribute selectors // Color mode toggle - d-none-main-* classes plus [data-bs-main-theme="dark"] compound selectors /d-none-main/, // Bootstrap transitions and utilities that get added via JS /fade/, /^translate/ // Bootstrap utilities ] } }) module.exports = { plugins: [ autoprefixer, cssnano, purgecss ] } ================================================ FILE: config/production/deployment.toml ================================================ # toml-docs-start az-blob # By default, files are uploaded in an arbitrary order. # Files that match the regular expressions in the "Order" list # will be uploaded first, in the listed order. order = [".webp$", ".jpg$", ".gif$"] [targets] name = "hinode" URL = "azblob://$web" [[matchers]] # Cache static assets for 1 year. pattern = "^.+\\.(js|css|svg|ttf)$" cacheControl = "max-age=31536000, no-transform, public" gzip = true [[matchers]] pattern = "^.+\\.(png|jpg|webp)$" cacheControl = "max-age=31536000, no-transform, public" gzip = false [[matchers]] # Set custom content type for /sitemap.xml pattern = "^sitemap\\.xml$" contentType = "application/xml" gzip = true [[matchers]] pattern = "^.+\\.(html|xml|json)$" gzip = true # toml-docs-end az-blob ================================================ FILE: config/production/hugo.toml ================================================ canonifyURLs = false ================================================ FILE: config/production/params.toml ================================================ # Production-specific parameters [style] purge = true [modules.hinode.csp] frame-ancestors = [ "'self'" ] ================================================ FILE: content/_index.md ================================================ --- title: Welcome to Hinode! description: A clean documentation and blog theme for your Hugo site based on Bootstrap 5. --- ================================================ FILE: content/_modals/_index.md ================================================ --- title: Modal elements cascade: - build: list: local publishResources: false render: never --- ================================================ FILE: data/.gitkeep ================================================ ================================================ FILE: data/dimensions.yml ================================================ - ratio: 4x3 dimensions: - 576x432 - 768x576 - 992x744 - 1200x900 - 1400x1050 - 2800x2100 - ratio: 3x1 dimensions: - 576x192 - 768x256 - 992x331 - 1200x400 - 1400x467 - 2800x933 - ratio: 3x2 dimensions: - 576x384 - 768x512 - 992x661 - 1200x800 - 1400x933 - 2800x1867 - ratio: 1x1 dimensions: - 576x576 - 768x768 - 992x992 - 1200x1200 - 1400x1400 - 2800x2800 - ratio: 16x9 dimensions: - 576x324 - 768x432 - 992x558 - 1200x675 - 1400x788 - 2800x1575 - ratio: 21x9 dimensions: - 576x247 - 768x329 - 992x425 - 1200x514 - 1400x600 - 2800x1200 - ratio: auto dimensions: - 576 - 768 - 992 - 1200 - 1400 - 2800 ================================================ FILE: data/netlify.toml ================================================ # toml-docs-start netlify [build] publish = "exampleSite/public" command = "HUGO_HINODE_VERSION=$(git describe --tags $(git rev-list --tags --max-count=1)) npm run build:example" [build.environment] DART_SASS_VERSION = "1.98.0" HUGO_VERSION = "0.153.1" HUGO_ENV = "production" HUGO_ENABLEGITINFO = "true" NODE_VERSION = "24.12.0" NPM_VERSION = "11.6.2" # toml-docs-end netlify [context.deploy-preview] command = "HUGO_HINODE_VERSION=$(git describe --tags $(git rev-list --tags --max-count=1)) npm run build:example -- -b $DEPLOY_PRIME_URL" [context.branch-deploy] command = "HUGO_HINODE_VERSION=$(git describe --tags $(git rev-list --tags --max-count=1)) npm run build:example -- -b $DEPLOY_PRIME_URL" [dev] framework = "#custom" command = "HUGO_HINODE_VERSION=$(git describe --tags $(git rev-list --tags --max-count=1)) npm run start:example" targetPort = 1313 port = 8888 publish = "public" autoLaunch = false # toml-docs-start plugins [[plugins]] package = "netlify-plugin-hugo-cache-resources" # toml-docs-end plugins ================================================ FILE: data/server.toml ================================================ # toml-docs-start server-config [[headers]] for = "/**" [headers.values] Strict-Transport-Security = "max-age=31536000; includeSubDomains; preload" X-Content-Type-Options = "nosniff" X-XSS-Protection = "1; mode=block" Referrer-Policy = "strict-origin" Permissions-Policy = """\ geolocation=(), \ midi=(), \ sync-xhr=(), \ microphone=(), \ camera=(), \ magnetometer=(), \ gyroscope=(), \ fullscreen=(), \ payment=() \ """ cache-control = """\ max-age=0, \ no-cache, \ no-store, \ must-revalidate \ """ Access-Control-Allow-Origin = "*" Content-Security-Policy = """\ default-src 'none'; \ script-src 'self'; \ font-src 'self'; \ connect-src 'self'; \ img-src 'self'; \ style-src 'self'; \ base-uri 'self'; \ object-src 'none'; \ form-action 'self'; \ manifest-src 'self'; \ media-src 'self' \ """ # toml-docs-end server-config ================================================ FILE: data/structures/abbr.yml ================================================ comment: >- Use the abbr shortcode to show the long form of an abbreviation. The abbreviation data is centrally stored in a data file with translation support. icon: spellcheck arguments: key: type: string position: 0 optional: false preview: true comment: >- Case-insensitive key of the abbreviation. In shorthand notation, this is the first (and only) matched argument. Non-alphanumeric keys must be quoted. data: type: string default: abbr optional: true comment: >- Filename of the abbreviation input. You can omit the file extension. The file should reside in the `data` folder. The data supports language extensions. For example, `abbr.en.yaml` refers to the English translation of the abbreviation data. The filename `abbr.yaml` is used when no suitable translation is found. class: type: string optional: true comment: >- Class attribute of the abbr element. For example, specify `initialism` for a slightly smaller font size. example: | {{< abbr HTML >}} ================================================ FILE: data/structures/accordion-item.yml ================================================ comment: >- Defines an individual accordion item. icon: expand_circle_down arguments: title: release: v1.0.0 preview: true show: class: # deprecated arguments header: type: string optional: true comment: Header of the accordion item. deprecated: v1.0.0 alternative: title body: optional: false comment: Content of the accordion item. group: shortcode example: | {{< accordion-item title="First item" show="true" >}} Content of the first accordion item. {{< /accordion-item >}} ================================================ FILE: data/structures/accordion.yml ================================================ comment: >- Use the accordion shortcode to show a group of vertically collapsing and expanding items. Add accordion-item inner elements for each item. icon: expand_all children: - accordion-item arguments: id: preview: true always-open: class: body: type: string optional: false group: shortcode comment: Inner elements for each panel. example: | {{< accordion id="accordion-example" always-open="true" >}} {{< accordion-item title="First item" show="true" >}} Content of the first accordion item. {{< /accordion-item >}} {{< accordion-item title="Second item" >}} Content of the second accordion item. {{< /accordion-item >}} {{< /accordion >}} ================================================ FILE: data/structures/alert.yml ================================================ comment: >- Use the alert shortcode to display a contextual feedback message. The inner content is used as alert text. icon: add_alert arguments: alert-type: release: v1.0.0 class: color: default: danger preview: true dismissible: icon: # deprecated arguments type: type: select optional: true comment: Type of the alert, generates an alert with related color and icon. options: values: - danger - info deprecated: v1.0.0 alternative: alert-type example: | {{< alert color="warning" dismissible="true" >}} This is a warning alert — check the settings before continuing. {{< /alert >}} body: optional: false comment: Alert text. group: shortcode ================================================ FILE: data/structures/args.yml ================================================ comment: >- Generates a table of structured arguments defined in a data file identified by a structure name. icon: table_chart arguments: page: optional: false group: partial structure: type: string position: 0 optional: false preview: true comment: >- Name of the data file that contains argument definitions. Supported data formats include JSON, TOML, YAML, and XML. You can omit the file extension. The file should reside in the `data/structures` folder. For bookshop components, add the `bookshop-` prefix to the structure name. group: type: string position: 1 optional: true comment: >- Name of the group filter. This is typically used when a shortcode and partial have common arguments. The group filter binds a specific argument to a particular group. By default, an argument belongs to all groups. parent: type: bool position: 2 optional: true comment: >- Flag to filter only arguments that have a parent attribute (either `cascade` or `merge`). render-type: type: select position: 3 default: both optional: true comment: >- Option whether to render arguments, user-defined types, or both. Please note that the arguments will render a link to a user-defined type in any case. options: values: - arguments - types - both release: v1.0.0 header-level: type: int default: 3 optional: true options: min: 1 max: 6 comment: >- The header level to use for the user-defined type headers. release: v1.0.0 example: | {{< args structure="alert" >}} ================================================ FILE: data/structures/background.yml ================================================ comment: >- Applies styling to the background of an element. group: partial arguments: background: class: ================================================ FILE: data/structures/badge.yml ================================================ comment: Use the badge shortcode to enrich headings. icon: badge arguments: title: preview: true class: color: default: secondary example: | {{< badge color="primary" >}}New{{< /badge >}} ================================================ FILE: data/structures/breadcrumb.yml ================================================ comment: >- Displays the current page's location within the site's navigational hierarchy. icon: segment arguments: page: path: preview: true example: | {{< breadcrumb >}} ================================================ FILE: data/structures/button-group.yml ================================================ comment: >- Displays a group of related buttons. Add button inner elements for each button. icon: buttons_alt children: - button arguments: label: preview: true aria-label: aria-role: release: v2.7.0 attributes: release: v2.7.0 body: type: string optional: false comment: Inner {{- end -}}
{{ or $args.raw ($args.body | $args.page.RenderString) | safeHTML }}
{{- else -}}
{{ or $args.raw ($args.body | $args.page.RenderString) | safeHTML }}
{{- end -}} {{- end -}} ================================================ FILE: layouts/_partials/assets/nav.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{- $error := false -}} {{- define "_partials/inline/nav-dropdown.html" -}} {{ $id := .id }} {{ $class := .class }} {{ $titles := .titles }} {{ $wrap := .wrap }} {{- end -}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "nav" "args" . "group" "partial") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "assets/nav.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File ) -}} {{- $error = $args.err -}} {{- end -}} {{/* Initialize global arguments */}} {{- $padding := partial "utilities/GetPadding.html" -}} {{- $breakpoint := partial "utilities/GetBreakpoint.html" -}} {{/* Initialize local arguments */}} {{- $page := $args.page -}} {{- $id := $args.id | default "0" -}} {{- $type := or $args.tabType $args.type -}} {{- $wrap := $args.wordWrap -}} {{- $isBtnGroup := eq $type "buttons" -}} {{- $isVertical := $args.vertical -}} {{- $align := cond (not $isVertical) $args.align "" -}} {{- $controlsPlacement := cond (not $isVertical) (or $args.controlsPlacement "top") "" -}} {{- $alignClass := cond (eq $align "center") " justify-content-center" (cond (eq $align "end") " justify-content-end" "") -}} {{- $titles := slice -}} {{- range $args.list }}{{ $titles = $titles | append .Title }} {{ end -}} {{- if reflect.IsSlice $args.navTitles }}{{ $titles = $titles | append $args.navTitles }}{{ end -}} {{- $icons := $args.navIcons -}} {{- $itemAttrs := $args.navItemAttrs -}} {{/* Tab-content class — spacing depends on type and controls-placement. tabs/callout: border acts as the visual separator, no margin needed. vertical: left margin to offset from the vertical nav rail. all others: top margin when controls are above (default). */}} {{- $tabContentSpacing := "" -}} {{- if $isVertical -}} {{- $tabContentSpacing = printf "ms-%s-3" $breakpoint.current -}} {{- else if and (not (in (slice "tabs" "callout") $type)) (ne $controlsPlacement "bottom") -}} {{- $tabContentSpacing = "mt-3" -}} {{- end -}} {{- $tabContentClass := printf "tab-content %s%s" (cond (in (slice "tabs" "callout") $type) "border p-3 bg-body " "") $tabContentSpacing -}} {{/* Main code */}} {{- if not $error -}}
{{- if $isVertical }}
{{ end -}} {{/* Responsive dropdown (standard nav types only, controls-top position) */}} {{- if and $args.responsive (not $isBtnGroup) (ne $controlsPlacement "bottom") -}} {{ partial "inline/nav-dropdown.html" (dict "id" $id "class" (printf "d-%s-none py-%d" $breakpoint.current $padding.y) "titles" $titles "wrap" $wrap ) }} {{- end -}} {{/* Tab content — rendered first when controls-placement=below */}} {{- if eq $controlsPlacement "bottom" -}}
{{- $args.navItems | safeHTML -}}
{{- end -}} {{/* Nav controls */}}
{{- if $isBtnGroup -}} {{/* buttons tab-type */}}
{{- range $index, $item := $titles -}} {{- $itemID := printf "%s-btn-%d" $id $index -}} {{- $show := eq $index 0 -}} {{- if $args.navShow }}{{- $show = eq $args.navShow $itemID -}}{{ end -}} {{- $disabled := in $args.navDisabled $itemID -}} {{- $itemIcon := index $icons $index -}} {{- $itemAttrMap := index $itemAttrs $index -}} {{- end -}}
{{- else -}} {{/* Standard nav (pills, tabs, underline, callout) */}} {{- end -}}
{{/* Tab content — rendered after controls by default (controls-placement=top) */}} {{- if ne $controlsPlacement "bottom" -}}
{{- $args.navItems | safeHTML -}}
{{- end -}} {{/* Responsive dropdown (standard nav types only, controls-below position) */}} {{- if and $args.responsive (not $isBtnGroup) (eq $controlsPlacement "bottom") -}} {{ partial "inline/nav-dropdown.html" (dict "id" $id "class" (printf "d-%s-none py-%d" $breakpoint.current $padding.y) "titles" $titles "wrap" $wrap ) }} {{- end -}} {{- if $isVertical }}
{{ end -}}
{{- end -}} ================================================ FILE: layouts/_partials/assets/navbar.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* TODO: consider to drop style arg */}} {{- define "_partials/inline/divider.html" -}} {{- $breakpoint := .breakpoint -}}
  • {{- end -}} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "navbar" "args" . "group" "partial") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "assets/navbar.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File )}} {{ end }} {{/* Initialize global variables */}} {{- $padding := partial "utilities/GetPadding.html" (dict "section" "navigation") -}} {{- $searchArgs := cond (in $args.default "search") (dict) (dict "search" $args.search) -}} {{- $search := partial "utilities/GetSearchConfig.html" $searchArgs -}} {{- $fs := site.Params.navigation.fontsizeCollapsed | default 6 -}} {{- $navbarOverflow := "fas ellipsis" -}} {{- $langIcon := "fas globe" -}} {{- $navbarOverflow := partial "utilities/GetThemeIcon.html" (dict "id" "navbarOverflow" "default" "fas ellipsis") -}} {{- $navbarLanguage := partial "utilities/GetThemeIcon.html" (dict "id" "navbarLanguage" "default" "fas globe") -}} {{- with site.Params.navigation.language.icon -}} {{- partial "utilities/LogWarn.html" (dict "partial" "assets/navbar.html" "warnid" "warn-deprecated-icons" "msg" "Deprecated icon params detected; migrate to the [icons] section in params.toml" "details" (slice "Replace 'navigation.language.icon' with 'icons.navbarLanguage'") ) -}} {{- end -}} {{/* Initialize local arguments */}} {{- $absoluteURL := site.Params.main.canonifyAssetsURLs | default false -}} {{- $pretty := site.Params.main.internalLinks.pretty | default false }} {{- $id := $args.id | default (printf "navbar-%d" 0) -}} {{- $page := $args.page -}} {{- $baseURL := $page.Scratch.Get "baseURL" -}} {{- $breakpoint := or $args.breakpoint $args.size }} {{- $defaultMenu := "main" -}} {{- $menuName := (or $args.menu $args.menus) | default $defaultMenu }} {{- $menu := index site.Menus $menuName -}} {{- if or (ne (printf "%T" $menu) "navigation.Menu") (ne (index $menu 0).Menu $menuName) -}} {{- if ne $menuName $defaultMenu }} {{- errorf "partial [assets/navbar.html] - Invalid value for param 'menus': %s" $menuName -}} {{- end -}} {{- end -}} {{- $overlay := $args.overlay | default false -}} {{- $overlayMode := $args.overlayMode | default "dark" -}} {{- if eq $overlayMode "none" }}{{ $overlayMode = "" }}{{ end }} {{- $color := $args.color | default "" -}} {{- $enableDarkMode := .mode | default (or site.Params.main.enableDarkMode site.Params.main.colorMode.enabled) -}} {{- $modes := site.Params.main.modes | default (slice "light" "dark") -}} {{ if isset site.Params.main "enabledarkmode" }} {{ warnf "site parameter %q: deprecated in v%s, use %q instead" "main.enableDarkMode" "1.12.0" "main.colorMode.enabled" }} {{ end }} {{ if isset site.Params.main "modes" }} {{ warnf "site parameter %q: deprecated in v%s, use %q instead" "main.modes" "1.12.0" "main.colorMode.modes" }} {{ end }} {{- $enableVersions := false -}} {{ $list := site.Params.docs.releases }} {{ if $list }} {{- $enableVersions = gt (len $list ) 1 -}} {{ end }} {{- $enableLanguage := or $page.IsTranslated hugo.IsMultilingual -}} {{- $horizontal := default false site.Params.navigation.horizontal -}} {{- $title := site.Title -}} {{- if $args.title -}} {{- $title = $args.title -}} {{- end -}} {{ $logo := "" }} {{ $mode := index site.Params.navigation "logo-mode" | default false }} {{ if (not (in $args.default "logo-mode")) }} {{ $mode = $args.logoMode }} {{ end }} {{ $align := index site.Params.navigation "logo-align" | default "center" }} {{ if (not (in $args.default "logo-align")) }} {{ $align = $args.logoAlign }} {{ end }} {{ if not $args.title }} {{ with $args.logo | default site.Params.navigation.logo }} {{ $height := index site.Params.navigation "logo-height" | default 30 }} {{ $class := cond (eq $align "start") "my-auto" "m-auto" }} {{ $logo = partial "assets/image.html" (dict "src" . "loading" "eager" "title" $title "image-height" $height "mode" $mode "class" $class ) }} {{ end }} {{ end }} {{- $class := $args.class -}} {{- $contrast := false -}} {{- if in (slice "primary" "secondary" "success" "danger") $color }}{{ $contrast = true }}{{ end -}} {{- $flex := false }} {{ if gt (where $menu "Params.spacing" true | len) 0 }} {{ $flex = true }} {{ end }} {{/* Main code */}}
    {{- partial "assets/page-alert.html" (dict "page" $page) -}}
    ================================================ FILE: layouts/_partials/assets/page-alert.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "page-alert" "args" . "group" "partial") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "assets/page-alert.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File )}} {{ end }} {{/* Initialize local arguments */}} {{- $pageAlertMsg := $args.page.Scratch.Get "pageAlertMsg" -}} {{- $pageAlertURL := $args.page.Scratch.Get "pageAlertURL" -}} {{- $version := $args.page.Scratch.Get "version" -}} {{/* Main code */}} {{- if and (not $args.err) $pageAlertMsg -}} {{- end -}} ================================================ FILE: layouts/_partials/assets/pagination.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. This source code adapts the original partial as maintained by the Hugo repository. It introduces the following modifications: - Centered the pagination element - Standardized validation of partial arguments - Replaced previous / next navigation with text The original source code is available on: https://github.com/gohugoio/hugo/blob/master/tpl/tplimpl/embedded/templates/pagination.html Copyright 2022 The Hugo Authors. Licensed under the Apache License, Version 2.0. */}} {{- define "_partials/inline/pagination/default" }} {{- $paginationFirst := partial "utilities/GetThemeIcon.html" (dict "id" "paginationFirst" "default" "fas angles-left") -}} {{- $paginationPrev := partial "utilities/GetThemeIcon.html" (dict "id" "paginationPrev" "default" "fas angle-left") -}} {{- $paginationNext := partial "utilities/GetThemeIcon.html" (dict "id" "paginationNext" "default" "fas angle-right") -}} {{- $paginationLast := partial "utilities/GetThemeIcon.html" (dict "id" "paginationLast" "default" "fas angles-right") -}} {{- with .Paginator }} {{- $currentPageNumber := .PageNumber }} {{- with .First }} {{- if ne $currentPageNumber .PageNumber }}
  • {{- else }}
  • {{- end }} {{- end }} {{- with .Prev }}
  • {{- else }}
  • {{- end }} {{- $slots := 5 }} {{- $start := math.Max 1 (sub .PageNumber (math.Floor (div $slots 2))) }} {{- $end := math.Min .TotalPages (sub (add $start $slots) 1) }} {{- if lt (add (sub $end $start) 1) $slots }} {{- $start = math.Max 1 (add (sub $end $slots) 1) }} {{- end }} {{- range $k := seq $start $end }} {{- if eq $.Paginator.PageNumber $k }}
  • {{ $k }}
  • {{- else }}
  • {{ $k }}
  • {{- end }} {{- end }} {{- with .Next }}
  • {{- else }}
  • {{- end }} {{- with .Last }} {{- if ne $currentPageNumber .PageNumber }}
  • {{- else }}
  • {{- end }} {{- end }} {{- end }} {{- end -}} {{- define "_partials/inline/pagination/terse" }} {{- $paginationFirst := partial "utilities/GetThemeIcon.html" (dict "id" "paginationFirst" "default" "fas angles-left") -}} {{- $paginationPrev := partial "utilities/GetThemeIcon.html" (dict "id" "paginationPrev" "default" "fas angle-left") -}} {{- $paginationNext := partial "utilities/GetThemeIcon.html" (dict "id" "paginationNext" "default" "fas angle-right") -}} {{- $paginationLast := partial "utilities/GetThemeIcon.html" (dict "id" "paginationLast" "default" "fas angles-right") -}} {{- with .Paginator }} {{- $currentPageNumber := .PageNumber }} {{- with .First }} {{- if ne $currentPageNumber .PageNumber }}
  • {{- end }} {{- end }} {{- with .Prev }}
  • {{- end }} {{- $slots := 3 }} {{- $start := math.Max 1 (sub .PageNumber (math.Floor (div $slots 2))) }} {{- $end := math.Min .TotalPages (sub (add $start $slots) 1) }} {{- if lt (add (sub $end $start) 1) $slots }} {{- $start = math.Max 1 (add (sub $end $slots) 1) }} {{- end }} {{- range $k := seq $start $end }} {{- if eq $.Paginator.PageNumber $k }}
  • {{ $k }}
  • {{- else }}
  • {{ $k }}
  • {{- end }} {{- end }} {{- with .Next }}
  • {{- end }} {{- with .Last }} {{- if ne $currentPageNumber .PageNumber }}
  • {{- end }} {{- end }} {{- end }} {{- end -}} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "pagination" "args" . "group" "partial") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "assets/pagination.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File )}} {{ end }} {{/* Main code */}} {{- if and (not $args.err) (gt $args.page.Paginator.TotalPages 1) }} {{- end }} ================================================ FILE: layouts/_partials/assets/persona.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "persona" "args" . "group" "partial") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "assets/persona.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File )}} {{ end }} {{/* Initialize local arguments */}} {{- $page := "" }} {{- if $args.path }} {{- $page = site.GetPage $args.path }} {{- if not $page }} {{- errorf "partial [assets/persona.html] - Cannot find page: %s" $args.path -}} {{- end }} {{- end }} {{- $title := $args.title -}} {{- $href := $args.href -}} {{- $content := $args.content -}} {{- $thumbnail := $args.thumbnail -}} {{- with $page -}} {{- if not $title }}{{ $title = .Title }}{{ end -}} {{- if not $href }}{{ $href = .RelPermalink }}{{ end -}} {{- if not $content }}{{ $content = .Content }}{{ end -}} {{- if not $thumbnail }} {{ if reflect.IsMap .Params.Thumbnail }} {{ $thumbnail = .Params.Thumbnail.url }} {{ else }} {{ $thumbnail = .Params.Thumbnail }} {{ end }} {{ end -}} {{- end -}} {{- $tab := site.Params.main.externalLinks.tab -}} {{- $isExternal := ne (urls.Parse (absURL $href)).Host (urls.Parse site.BaseURL).Host -}} {{- $target := "" -}} {{- $rel := "" -}} {{- if and $isExternal $tab -}} {{- $target = "_blank" -}} {{- $rel = "noopener noreferrer nofollow" -}} {{- end -}} {{/* Inline partial to render the card's body */}} {{- define "_partials/inline/persona-body.html" -}} {{- $title := .title -}} {{- $content := .content -}}
    {{ $title }}
    {{ with $content }}

    {{ . }}

    {{ end -}} {{- end -}} {{/* Main code */}} {{- if not $args.err -}} {{ with $href }} {{ end }} {{ $illustration := "" }} {{- if $thumbnail -}} {{- $illustration = partial "assets/image.html" (dict "src" $thumbnail "title" $title "ratio" "1x1" "class" "rounded-5" "loading" $args.loading ) -}} {{ end }}
    {{ $illustration }}
    {{- partial "inline/persona-body.html" (dict "title" $title "content" $content) -}}
    {{ $illustration }}
    {{- partial "inline/persona-body.html" (dict "title" $title "content" $content) -}}
    {{ if $href }}
    {{ end }} {{ end }} ================================================ FILE: layouts/_partials/assets/section-title.html ================================================ {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "section-title" "args" . "group" "partial") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "assets/section-title.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File )}} {{ end }} {{/* Initialize global arguments */}} {{- $breakpoint := partial "utilities/GetBreakpoint.html" -}} {{- $padding := partial "utilities/GetPadding.html" -}} {{/* Initialize local arguments */}} {{- $size := (or $args.heading.size site.Params.style.title.size) | default 4 -}} {{- $arrangement := (or $args.arrangement site.Params.style.title.arrangement) | default "above" -}} {{- $headingStyle := (or $args.headingStyle site.Params.style.title.headingStyle) | default "display" -}} {{- $contentStyle := (or $args.contentStyle site.Params.style.title.contentStyle) | default "lead text-muted" -}} {{- $preheading := $args.heading.preheading }} {{- $title := $args.heading.title }} {{- $width := $args.heading.width | default 12 -}} {{- $width = cond (lt $width 12) (printf "col-12 col-%s-%d" $breakpoint.current $width) "" }} {{- if and (not $preheading) $args.useSection }}{{ $preheading = page.CurrentSection.Name }}{{ end -}} {{- $justify := cond (eq $args.justify "start") "" (cond (eq $args.justify "end") "me-0" "mx-auto") -}} {{ if and site.Params.main.titleCase (not $args.page.Params.exact) }} {{ $preheading = title $preheading }} {{ $title = title $title }} {{ end }} {{ define "_partials/assets/section-title-header.html" }} {{ $headingStyle := .headingStyle }} {{ if (index . "use-title") }} {{ $title := .title | page.RenderString }} {{ $label := trim (replaceRE "\r\n?|\n" " " ($title | plainify)) " " }}

    {{ .title | page.RenderString | safeHTML }}

    {{ else }}
    {{ .title | page.RenderString | safeHTML }}
    {{ end }} {{ end }} {{ $header := "" }} {{ if $title }} {{ $header = partial "assets/section-title-header.html" (dict "use-title" $args.useTitle "title" $title "headingStyle" $headingStyle "color" $args.color "size" $size ) }} {{ end }} {{ $links := "" }} {{ if $args.links }} {{ $links = partial "assets/links.html" (dict "page" $args.page "links" $args.links "align" $args.heading.align "justify" $args.justify "link-type" $args.linkType ) }} {{ end }} {{/* Main code */}} {{ if or $args.heading.title $args.heading.content }}
    {{ if and $preheading (eq $arrangement "first") }}
    {{ with $preheading }}

    {{ . | page.RenderString | safeHTML }}

    {{ end }}
    {{ $header }} {{ with $args.heading.content }}
    {{ . | page.RenderString | safeHTML }}
    {{ end }} {{ $links }}
    {{/* Place above */}} {{ else }} {{ with $preheading }}

    {{ . | page.RenderString | safeHTML }}

    {{ end }} {{ $header }} {{ with $args.heading.content }}
    {{ . | page.RenderString | safeHTML }}
    {{ end }} {{ $links }} {{ end }}
    {{ end }} ================================================ FILE: layouts/_partials/assets/sidebar.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "sidebar" "args" . "group" "partial") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "assets/sidebar.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File )}} {{ end }} {{/* Initialize local arguments */}} {{- $section := $args.page.Section }} {{/* Auto-generate hierarchical menu if enabled and no menu provided */}} {{- if and $args.autoGenerate (not $args.menu) -}} {{- $result := partial "assets/live-pages.html" (dict "page" $args.page "section" $section "nested" $args.nested "sort" "weight" "reverse" "false" "group-by" "section" "include-list" true "exclude-filtered" true ) -}} {{- /* Skip root section page and only show its children in sidebar */ -}} {{- $menu := $result.menu -}} {{- if and (gt (len $menu) 0) (index $menu 0).pages -}} {{- /* Root item has children - use only children, skipping the root */ -}} {{- $menu = (index $menu 0).pages -}} {{- end -}} {{- $args = merge $args (dict "menu" $menu) -}} {{- end -}} {{- define "_partials/inline/sidebar/group-link.html" -}} {{- $page := .page -}} {{- $group := .group -}} {{- $baseURL := .baseURL -}} {{- $pre := $group.pre -}} {{- $collapsible := .collapsible | default false -}} {{- $href := $group.link | default "" -}} {{- if and $href (not (hasPrefix $href "/")) -}} {{- $href = partial "utilities/URLJoin.html" (dict "base" $baseURL "path" $href) -}} {{- end -}} {{- if and $href (not (hasSuffix $href "/")) -}}{{- $href = printf "%s/" $href -}}{{- end -}} {{- $active := and $href (strings.HasPrefix $page.RelPermalink $href) -}} {{- $groupTitle := $group.title -}} {{- if and site.Params.main.titleCase (not $page.Params.exact) -}} {{- $groupTitle = title $groupTitle -}} {{- end -}}
  • {{- with $pre -}} {{- if hasPrefix . "{{- $groupTitle -}} {{- else -}} {{- $groupTitle -}} {{- end -}}
  • {{- end -}} {{- define "_partials/inline/sidebar/group.html" -}} {{- $page := .page -}} {{- $index := .index -}} {{- $level := .level -}} {{- $baseURL := .baseURL -}} {{- $group := .group -}} {{- $data := .menu -}} {{- $pre := $group.pre -}} {{- $doc_slug := partial "utilities/URLJoin.html" (dict "base" $baseURL "path" ($group.title | urlize)) -}} {{- $href := or $group.link $doc_slug -}} {{- /* Handle absolute paths from hierarchical menu (starting with /) */ -}} {{- if and $group.link (hasPrefix $group.link "/") -}} {{- $href = $group.link -}} {{- else if $group.link -}} {{- /* Non-absolute link provided - use URLJoin */ -}} {{- $href = partial "utilities/URLJoin.html" (dict "base" $baseURL "path" $group.link) -}} {{- end -}} {{ $ref := partial "utilities/GetPage.html" (dict "url" $href "page" $page) }} {{ if eq $group.link "#" }}{{ $href = $doc_slug }}{{ end }} {{- $collapsed := strings.HasPrefix $page.RelPermalink $href -}} {{ if not (hasSuffix $href "/") }}{{ $href = printf "%s/" $href }}{{ end }} {{- $current := eq $href $page.RelPermalink }}
  • {{ end -}} {{- define "_partials/inline/sidebar/item.html" -}} {{- $page := .page -}} {{- $level := .level -}} {{- $baseURL := .baseURL -}} {{- $title := .title -}} {{- $data := .menu -}} {{- $pre := .pre -}} {{- $collapsible := .collapsible | default false -}} {{- $prefixMatch := .prefixMatch | default false -}} {{- if and site.Params.main.titleCase (not $page.Params.exact) -}} {{- $title = title $title -}} {{- end -}} {{- $titleText := $title -}} {{- if $collapsible -}} {{- $titleText = printf "%s" $title -}} {{- end -}} {{- $itemText := $titleText -}} {{- with $pre -}} {{- $iconHTML := partial "assets/icon.html" (dict "icon" (string .) "class" "fa-fw me-1" "spacing" false) -}} {{- $itemText = printf "%s%s" (string $iconHTML) $titleText -}} {{- end -}} {{ $href := "" }} {{ with .href }} {{ if hasPrefix . "http" }} {{ $href = . }} {{ else if hasPrefix . "/" }} {{- /* Absolute path (from hierarchical menu) - use directly */ -}} {{ $href = . }} {{ else }} {{- /* Relative path - join with baseURL */ -}} {{- $href = partial "utilities/URLJoin.html" (dict "base" $baseURL "path" .) -}} {{ if not (hasSuffix $href "/") }}{{ $href = printf "%s/" $href }}{{ end }} {{ end }} {{ else }} {{- $href = partial "utilities/URLJoin.html" (dict "base" $baseURL "path" ($title | urlize)) -}} {{ if not (hasSuffix $href "/") }}{{ $href = printf "%s/" $href }}{{ end }} {{ end }} {{- $active := or (eq (strings.TrimSuffix "/" $page.RelPermalink) (strings.TrimSuffix "/" $href)) (and $prefixMatch $href (strings.HasPrefix $page.RelPermalink $href)) -}} {{ if eq $level 0}}
    • {{ $class := "sidebar-item text-decoration-none rounded w-100" }} {{ if $active }}{{ $class = printf "%s active" $class }}{{ end }} {{ $link := partial "assets/link.html" (dict "href" $href "text" $itemText "class" $class "page" $page "exact" true) }} {{- if and $collapsible $title $link -}} {{- $link = $link | replaceRE `(
  • {{ else }}
  • {{ $class := "sidebar-item text-decoration-none rounded small w-100" }} {{ if $active }}{{ $class = printf "%s active" $class }}{{ end }} {{ $link := partial "assets/link.html" (dict "href" $href "text" $itemText "class" $class "page" $page "exact" true) }} {{ if $link }} {{ print $link | safeHTML }} {{ else }} {{- errorf "partial [utilities/sidebar.html] - Invalid link in file: %s" ($page.Scratch.Get "sidebarFilename") -}} {{ end }}
  • {{ end }} {{ end -}} {{/* Main code */}} {{ if and (not $args.error) $args.menu }} {{- $levelMin := $args.levelMin | default 0 -}} {{- $levelMax := $args.levelMax | default 0 -}} {{- $collapsible := $args.collapsible | default false -}} {{- $page := $args.page -}} {{- $iconCollapse := partial "utilities/GetThemeIcon.html" (dict "id" "sidebarCollapse" "default" "fas angles-left") -}} {{- $iconSecondary := partial "utilities/GetThemeIcon.html" (dict "id" "sidebarSecondary" "default" "fas angle-up") -}} {{- $hasSpacerItem := gt (len (where $args.menu "spacer" true)) 0 -}} {{- $sidebarId := $section | urlize | default "sidebar" -}}
    {{ end }} ================================================ FILE: layouts/_partials/assets/spinner.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "spinner" "args" . "group" "partial") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "assets/spinner.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File )}} {{- end -}} {{/* Main code */}} {{- if not $args.err -}} {{- with $args.class }}
    {{ end -}}
    {{ or $args.label (T "loading") }}
    {{- if $args.class }}
    {{ end -}} {{- end -}} ================================================ FILE: layouts/_partials/assets/stack.html ================================================ {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "stack" "child" "card" "args" . "group" "partial") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "assets/stack.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File )}} {{ end }} {{/* Main code */}} {{ if not $args.err }} {{ if and (eq (len $args.list) 0) (not $args.hideEmpty) }}

    {{- T "emptyList" }}.

    {{ else }} {{ $params := dict "page" $args.page "list" $args.list "limit" (or $args.limit $args.max) "class" "border-0 card-zoom" "header-style" "none" "body-style" "title" "footer-style" "none" "href" $args.href "href-force" $args.hrefForce "href-title" $args.hrefTitle "link-type" (or $args.linkType $args.buttonType) "link-icon" $args.linkIcon }} {{- partial "assets/card-group.html" (merge $params (dict "cols" $args.cols "gutter" $args.gutter "padding" $args.padding "orientation" "stacked" "scroll" true "bento" true "spacer" $args.animated "portrait" false "valign" (cond $args.animated "" "end") "styles" $args.styles "wrapper" "card-stack p-0 my-3 d-none d-md-block" )) -}} {{- partial "assets/card-group.html" (merge $params (dict "cols" (cond (eq $args.orientation "stacked") 2 1) "responsive" false "padding" (cond (gt $args.padding 0) $args.padding 3) "orientation" $args.orientation "ratio" $args.ratio "scroll" false "spacer" false "portrait" false "wrapper" "card-stack p-0 d-md-none" )) -}} {{ end }} {{ end }} ================================================ FILE: layouts/_partials/assets/table.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ define "_partials/inline/table.html" }} {{ $page := .page }} {{ $input := .input }} {{ $attributes := .attributes }} {{ $class := .class }} {{ $wrap := .wrap }} {{ if $wrap }}{{ $input = printf "%s\n{.table-wrap}" (chomp $input) }}{{ end }} {{- $input = $input | $page.RenderString }} {{ $regex := `
    {{ range $filter }} {{ end }}
    {{ end }} {{ if eq $args.breakpoint "none" }} {{ $regular | safeHTML }} {{ with $wrapped }} {{ if $wrapper }}
    {{ . | safeHTML }}
    {{ else }}{{ . | safeHTML }}{{ end }} {{ end }} {{ else }}
    {{ $regular | safeHTML }}
    {{ with $wrapped }}
    {{ . | safeHTML }}
    {{ end }} {{ end }} {{ end }} ================================================ FILE: layouts/_partials/assets/testimonial.html ================================================ {{ define "_partials/inline/testimonial-contact.html" }}
    {{- partial "assets/live-image.html" (dict "src" .image "ratio" "1x1" "class" .class "title" .contact "mode" false "sizes" "(min-width: 768px) 5vw, 10vw" "page" .page ) }}
    {{ if .url }} {{ partial "assets/link.html" (dict "href" .url "text" .contact "page" .page "class" (cond .color (printf "fw-bold link-bg-%s" .color) "fw-bold") ) }} {{ else }} {{ .contact }} {{ end }}
    {{ with .role }}
    {{ . }}
    {{ end }}
    {{ end }} {{ define "_partials/inline/testimonial-minimal.html" }} {{ $class := (index . "icon-style") | default "fa-2xl text-center" }} {{ $wrapper := printf "text-%s" (.align | default "start") }} {{ if and (not .icon) .logo }}{{ $class = "testimonial-logo" }}{{ end }} {{ $title := trim (printf "%s logo" (humanize (path.BaseName .logo))) " ." }} {{ partial "assets/featured-illustration.html" (dict "page" .page "image" .logo "icon" .icon "class" $class "wrapper" $wrapper "title" $title ) }} {{ end }} {{ define "_partials/inline/testimonial-inner.html" }} {{ $breakpoint := .breakpoint }} {{- $testimonialNext := partial "utilities/GetThemeIcon.html" (dict "id" "testimonialNext" "default" "fas chevron-right") -}} {{ $align := .align | default "start" }}
    {{ if or .logo .icon }}
    {{ $wrapper := cond .logo (printf "py-4 py-md-0 col-4 col-%s-2" $breakpoint.current) "" }} {{ $class := "" }} {{ if .icon }} {{ $class = index . "icon-style" | default ""}} {{ with .align }}{{ $wrapper = printf "text-%s" . }}{{ end }} {{ end }} {{ if and (not .icon) .logo }}{{ $class = "testimonial-logo" }}{{ end }} {{ $title := trim (printf "%s logo" (humanize (path.BaseName .logo))) " ." }} {{ partial "assets/featured-illustration.html" (dict "page" .page "image" .logo "icon" .icon "class" $class "title" $title "wrapper" $wrapper ) }}
    {{ end }} {{ if .content }}
    {{ .content | .page.RenderString }}
    {{ end }} {{ if or .contact .link }}
    {{ if and .image .contact (not (eq .orientation "horizontal")) }} {{ partial "inline/testimonial-contact.html" (dict "page" .page "image" .image "contact" .contact "role" .role "url" .url "color" .color "align" "start" "class" "rounded-circle testimonial-img" )}} {{ else if .link }} {{ partial "assets/button.html" (dict "href" .link "title" (T "testimonialCase") "class" "btn-testimonial" "icon" $testimonialNext "outline" true ) }} {{ end }}
    {{ end }}
    {{ end }} {{ define "_partials/inline/testimonial-card.html" }} {{ $breakpoint := .breakpoint }} {{ if and .image .contact (eq .orientation "horizontal") }}
    {{ partial "inline/testimonial-contact.html" (dict "page" .page "image" .image "contact" .contact "role" .role "url" .url "color" .color "align" "center" "class" "rounded-circle text-center" )}}
    {{ partial "inline/testimonial-inner.html" . }}
    {{ else if and (or .logo .icon) (not .content) (not .contact) (not .link) }} {{ partial "inline/testimonial-minimal.html" . }} {{ else }} {{ partial "inline/testimonial-inner.html" . }} {{ end }} {{ end }} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "testimonial" "args" . "group" "partial") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "assets/testimonial.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File )}} {{ end }} {{/* Initialize global variables */}} {{- $breakpoint := partial "utilities/GetBreakpoint.html" -}} {{- $testimonialQuote := partial "utilities/GetThemeIcon.html" (dict "id" "testimonialQuote" "default" "fas quote-right") -}} {{/* Initialize local variables */}} {{- $link := "" -}} {{ with $args.link }} {{ $href := partial "utilities/GetLink.html" (dict "page" $args.page "href" .) }} {{ if not $href.error }} {{ $link = $href.href }} {{ else }} {{ with $args.page.File }} {{ warnf "Error processing link on page '%s': %s" (path.Join "/content" .Path) $href.msg }} {{ else }} {{ warnf "Error processing link: %s" $href.msg }} {{ end }} {{ end }} {{ end }} {{/* Main code */}} {{ if not $args.err }}
    {{ $params := dict "page" $args.page "content" $args.content "icon" $args.icon "icon-style" $args.iconStyle "logo" $args.logo "contact" $args.contact "role" $args.role "image" $args.image "padding" $args.padding "orientation" $args.orientation "url" $args.url "link" $link "color" $args.color "breakpoint" $breakpoint "align" $args.align }} {{ if $args.showControls }}
    {{ partial "inline/testimonial-card.html" (merge $params (dict "class" "col-8 px-0 mb-5")) }}
    {{ partial "assets/icon.html" (dict "icon" $testimonialQuote "class" "fa-2x" "spacing" false) }}
    {{ else }} {{ partial "inline/testimonial-card.html" $params }} {{ end }}
    {{ end }} ================================================ FILE: layouts/_partials/assets/timeline.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. Inspired by the timeline snippet from Siddharth Panchal at https://bootsnipp.com/snippets/Q0ppE */}} {{ $error := false }} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "timeline" "args" . "group" "partial" )}} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "assets/timeline.html" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File )}} {{ $error = $args.err }} {{ end }} {{/* Initialize global variables */}} {{ $arrangement := or (index site.Params "style" "title" "arrangement") "above" }} {{- $padding := partial "utilities/GetPadding.html" -}} {{/* Initialize local arguments */}} {{- $page := $args.page -}} {{- $data := "" -}} {{- with $args.data -}}{{- $data = partial "utilities/GetI18nData.html" (dict "page" $page "data" .) -}}{{- end -}} {{- if and (not $data) (not $args.section) -}} {{ partial "utilities/LogErr.html" (dict "partial" "assets/timeline.html" "msg" "Invalid arguments" "details" (slice (printf "Invalid timeline data '%s'" $args.data)) "file" page.File )}} {{ $error = true }} {{- end -}} {{/* Override data from a Hugo content section when section is provided */}} {{- if $args.section -}} {{- $sectionPage := site.GetPage $args.section -}} {{- if $sectionPage -}} {{- $pages := $sectionPage.RegularPages.ByDate.Reverse -}} {{- $sectionData := slice -}} {{- range $pages -}} {{- $sectionData = $sectionData | append (dict "title" .Title "date" .Date "content" .Description "url" .RelPermalink "color" "primary" ) -}} {{- end -}} {{- $data = $sectionData -}} {{- else -}} {{- partial "utilities/LogWarn.html" (dict "partial" "assets/timeline.html" "warnid" "warn-invalid-section" "msg" "Invalid section" "details" (slice (printf "Section '%s' not found" $args.section)) "file" page.File ) -}} {{- end -}} {{- end -}} {{/* Apply limit */}} {{- if and $args.limit (gt (len $data) $args.limit) -}} {{- $data = first $args.limit $data -}} {{- end -}} {{ $background := partial "utilities/GetBackgroundStyle.html" (dict "background" $args.background) }} {{/* Inline partial to render icon */}} {{- define "_partials/inline/timeline-icon.html" -}} {{- $col := default 6 .col -}} {{- $icon := .icon -}} {{- $class := .class -}} {{- $direction := .direction -}}
    {{ partial "assets/icon.html" (dict "icon" $icon "class" (cond $class $class "fa-fluid") "wrapper" "fa-wrapper" "spacing" false ) }}
    {{- end -}} {{/* Inline partial to render icon */}} {{- define "_partials/inline/timeline-panel.html" -}} {{- $col := default 6 .col -}} {{- $page := .page -}} {{- $content := .content -}} {{- $color := .color -}} {{- $title := .title -}} {{- $badge := .badge -}} {{- $url := .url -}} {{- $date := .date -}} {{- if and $url (not (hasPrefix $url "http")) -}} {{- $url = partial "utilities/URLJoin.html" (dict "base" site.Params.docs.release "path" $url) }} {{- end -}} {{- $direction := .direction -}}
    {{ with $url }} {{ $title }} {{ if $badge }}{{ $badge }}{{ end }} {{ else}} {{ $title }} {{ if $badge }}{{ $badge }}{{ end }} {{ end }}
    {{ if $date }} {{ $datestr := (partial "utilities/date.html" (dict "date" $date "format" "long")) -}}

    {{ $datestr -}}

    {{ end }}

    {{ $content | markdownify }}

    {{- end -}} {{/* Main code */}} {{ if not $error }} {{ $title := "" }} {{ if $args.heading }} {{ $title = partial "assets/section-title.html" (dict "heading" $args.heading "use-title" $args.useTitle "size" $args.size "links" $args.links "link-type" (or $args.linkType $args.type) "arrangement" $arrangement "justify" $args.justify "class" (printf "pb-%d" $padding.y) ) }} {{ end }} {{/* Render start (compact start-aligned) timeline */}} {{ if eq $args.layout "start" }} {{ $title | safeHTML }}
      {{ range $data }}
    • {{- $datestr := "" -}} {{- with .date -}} {{- $datestr = partial "utilities/date.html" (dict "date" . "format" "long") -}} {{- end -}} {{ if and .url $datestr }} {{ $datestr }} {{ else if $datestr }} {{ $datestr }} {{ else if .url }} {{ .title }} {{ end }} {{ with .content }}

      {{ . | truncate 50 }}

      {{ end }}
    • {{ end }}
    {{/* Render default timeline */}} {{ else }}
    {{ $title | safeHTML }} {{ range $index, $item := $data }}
    {{- $params := dict "page" $args.page "content" $item.content "color" $item.color "title" $item.title "badge" $item.badge "date" $item.date "url" $item.url }} {{ if eq (mod $index 2) 1 }} {{ partial "inline/timeline-panel.html" (merge $params (dict "direction" "start")) }} {{ partial "inline/timeline-icon.html" (dict "icon" $item.icon "direction" "start") }} {{ else }} {{ partial "inline/timeline-icon.html" (dict "icon" $item.icon "direction" "end") }} {{ partial "inline/timeline-panel.html" (merge $params (dict "direction" "end")) }} {{ end }}
    {{ end }}
    {{/* Render timeline for smaller devices */}}
    {{ range $index, $item := $data }}
    {{ partial "inline/timeline-icon.html" (dict "icon" $item.icon "class" "fa-2xl" "direction" "end" "col" 3) }} {{ partial "inline/timeline-panel.html" (dict "page" $args.page "content" $item.content "color" $item.color "title" $item.title "badge" $item.badge "date" $item.date "url" $item.url "direction" "end" "col" 9 ) }}
    {{ end }}
    {{ end }}{{/* end layout branch */}} {{ end }} ================================================ FILE: layouts/_partials/assets/toast.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $error := false }} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "toast" "args" . "group" "partial")}} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "assets/toast.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File )}} {{ $error = $args.err }} {{ end }} {{/* Initialize arguments */}} {{- $id := $args.id | default (printf "toast-message-%d" 0) -}} {{ $title := (or $args.title $args.header) | default site.Title -}} {{/* Main code */}} ================================================ FILE: layouts/_partials/assets/toc-dropdown.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $error := false }} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "toc" "args" . "group" "partial") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "assets/toc.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File )}} {{ $error = $args.err }} {{ end }} {{/* Initialize local arguments */}} {{- $startLevel := or (.Site.Params.navigation.startLevel | int) 2 }} {{- $endLevel := or (.Site.Params.navigation.endLevel | int) 3 }} {{- $minNumHeadings := or (.Site.Params.navigation.minNumHeadings | int) 2 }} {{- $tocSort := partial "utilities/GetThemeIcon.html" (dict "id" "tocSort" "default" "fas sort") -}} {{/* Main code */}} {{ if not $error }} {{ $headings := partial "assets/toc-headings.html" $args.page }} {{- with $headings }} {{- if and (not $error) (ge (len .) $minNumHeadings) }}
    {{ partial "assets/button.html" (dict "title" (T "toc") "color" "secondary" "outline" "true" "class" "toc-button" "icon" $tocSort "justify" "between" "collapse-id" "toc-collapse" "order" "last" "spacing" false ) -}}
    {{- end }} {{- end }} {{- end }} ================================================ FILE: layouts/_partials/assets/toc-headings.html ================================================ {{- /* Copyright 2023 Veriphor, LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */}} {{- /* Initialize. */}} {{- $partialName := "toc-headings" }} {{- /* Verify minimum required version. */}} {{- $minHugoVersion := "0.125.6" }} {{- if lt hugo.Version $minHugoVersion }} {{- errorf "The %q partial requires Hugo v%s or later." $partialName $minHugoVersion }} {{- end }} {{- /* Determine content path for warning and error messages. */}} {{- $contentPath := "" }} {{- with .File }} {{- $contentPath = .Path }} {{- else }} {{- $contentPath = .Path }} {{- end }} {{- /* Get configuration. */}} {{- $startLevel := or (.Site.Params.navigation.startLevel | int) 2 }} {{- $endLevel := or (.Site.Params.navigation.endLevel | int) 3 }} {{- /* Get headings. */}} {{- $headings := slice }} {{- $ids := slice }} {{- range findRE `(?is)` .Content }} {{- $level := substr . 2 1 | int }} {{- if and (ge $level $startLevel) (le $level $endLevel) }} {{- $text := replaceRE `(?is)(.+?)` "$1" . }} {{- $text = trim $text " " | plainify }} {{/* Trim leading/trailing whitespace and   entities — the icon partial emits a trailing   for spacing, which would otherwise indent the TOC label. */}} {{- $text = replaceRE `^(?:\s| )+|(?:\s| )+$` "" $text | safeHTML }} {{- $id := "" }} {{- if findRE `\s+id=` . }} {{- $id = replaceRE `(?is).+?\s+id=(?:\x22|\x27)?(.*?)(?:\x22|\x27)?[\s>].+` "$1" . }} {{- $ids = $ids | append $id }} {{- if not $id }} {{- errorf "The %q partial detected that the %q heading has an empty ID attribute. See %s" $partialName $text $contentPath }} {{- end }} {{- else }} {{- errorf "The %q partial detected that the %q heading does not have an ID attribute. See %s" $partialName $text $contentPath }} {{- end }} {{- $headings = $headings | append (dict "id" $id "level" $level "text" $text) }} {{- end }} {{- end }} {{- /* Check for duplicate heading IDs. */}} {{- $unique := slice }} {{- $duplicates := slice }} {{- range $ids }} {{- if in $unique . }} {{- $duplicates = $duplicates | append . }} {{- else }} {{- $unique = $unique | append . }} {{- end }} {{- end }} {{- with $duplicates }} {{- errorf "The %q partial detected duplicate heading IDs (%s) in %s" $partialName (delimit . ", ") $contentPath }} {{- end }} {{ return $headings }} ================================================ FILE: layouts/_partials/assets/toc-main.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $headings := .headings | default slice }} {{- range .Fragments.Headings }} {{- range .Headings }} {{- $headings = $headings | append .Title -}} {{- end -}} {{- end -}} {{- if gt (len $headings) 1 }} {{- end }} ================================================ FILE: layouts/_partials/assets/toc-parse-content.html ================================================ {{/* Copyright © 2025 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ define "_partials/inline/toc-item.html" }} {{ $base := .base }} {{ $startLevel := .startLevel }} {{ $endLevel := .endLevel }} {{ $item := .item }} {{ $maxNumHeadings := .maxNumHeadings }} {{ $result := .result | default slice }} {{ if and (ge $item.Level $startLevel) (le $item.Level $endLevel) }} {{- $attrs := dict "class" (printf "toc-item toc-level-%d" (add 1 (sub $item.Level $startLevel))) }} {{- with $item.ID }} {{/* Strip Hugo's HAHAHUGOSHORTCODE placeholder — see _markup/render-heading.html. */}} {{- $cleanID := replaceRE `(?i)hahahugoshortcode\d+s\d+hbhb` "-" . -}} {{- $cleanID = trim (replaceRE `-+` "-" $cleanID) "-" -}} {{- $attrs = merge $attrs (dict "href" (printf "%s#%s" $base $cleanID)) }} {{- end }} {{ $htmlAttr := "" }} {{ range $k, $v := $attrs }}{{ $htmlAttr = printf "%s %s=%q" $htmlAttr $k $v | safeHTMLAttr }}{{ end }} {{- $cleanTitle := replaceRE `(?i)HAHAHUGOSHORTCODE\d+s\d+HBHB` " " $item.Title -}} {{- $cleanTitle = trim (replaceRE `\s+` " " $cleanTitle) " " -}} {{ $rendered := printf "%s" $htmlAttr $cleanTitle }} {{ $result = $result | append $rendered }} {{ end }} {{ if lt $item.Level $endLevel }} {{ range $item.Headings }} {{ $result = $result | append (partial "inline/toc-item.html" (dict "base" $base "item" . "startLevel" $startLevel "endLevel" $endLevel "maxNumHeadings" $maxNumHeadings )) }} {{ end }} {{ end }} {{ return $result }} {{ end }} {{- /* Get configuration. */}} {{- $startLevel := or (.Site.Params.navigation.startLevel | int) 2 }} {{- $endLevel := or (.Site.Params.navigation.endLevel | int) 3 }} {{- $minNumHeadings := or (.Site.Params.navigation.minNumHeadings | int) 2 }} {{- $maxNumHeadings := or (.Site.Params.navigation.maxNumHeadings | int) 9 }} {{- /* Render */}} {{- if .Site.Params.navigation.toc }} {{- /* Check for custom headings in Page.Store or Page.Params, otherwise use Page.Fragments */}} {{- $customHeadings := .Page.Store.Get "Headings" }} {{- $customHeadingsMap := .Page.Store.Get "HeadingsMap" }} {{- if not $customHeadings }} {{- $customHeadings = .Page.Params.Headings }} {{- $customHeadingsMap = .Page.Params.HeadingsMap }} {{- end }} {{- $fragments := cond $customHeadings (dict "Headings" $customHeadings "HeadingsMap" $customHeadingsMap) .Page.Fragments }} {{- with $fragments }} {{- if (ge (len .HeadingsMap) $minNumHeadings) }} {{ T "toc" }} {{ end }} {{ end }} {{ end }} ================================================ FILE: layouts/_partials/assets/toc.html ================================================ {{/* Copyright © 2024-2025 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "toc" "args" . "group" "partial")}} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "assets/toc.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File )}} {{ $error = $args.err }} {{ end }} {{/* Main code */}} {{ if not $args.err -}} {{ partial "assets/toc-parse-content.html" $args.page }} {{ end -}} ================================================ FILE: layouts/_partials/assets/version.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Retrieves the Hinode theme version from the site's go.mod file (when initialized as module.) */}} {{- define "_partials/inline/mod-version.html" -}} {{- $file := "go.mod" -}} {{- $regex := printf `github.com/gethinode/hinode(\/v[0-9]+)? v.*(\r\n|\r|\n)` -}} {{- $match := findRE $regex (readFile $file) -}} {{- $result := "" -}} {{- if gt (len $match) 0 -}} {{- $result = (index (split (index $match 0) " ") 1) -}} {{- $result = strings.TrimPrefix "v" $result -}} {{- end -}} {{- return $result -}} {{- end -}} {{/* Fallback to initialize the Hinode version from an environment variable. This applies to the main Hinode repository including the example site (which is published to demo.gethinode.com). The following command initializes the HUGO_HINODE_VERSION using the relevant git tag on macOS/Linux: HUGO_HINODE_VERSION=$(git describe --tags $(git rev-list --tags --max-count=1)) npm run build:example */}} {{- define "_partials/inline/env-version.html" -}} {{ return getenv "HUGO_HINODE_VERSION" }} {{- end -}} {{- $version := partial "inline/mod-version.html" . -}} {{ if not $version }} {{- $version = partial "inline/env-version.html" . | default "unknown-revision" -}} {{ end }} {{- print $version -}} ================================================ FILE: layouts/_partials/assets/video.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. This source code adapts the original embedded shortcode as maintained by the Hugo repository. It introduces the following modifications: - Isolated the styles to comply with the Content Security Policy - Added validation of shortcode arguments - Added support to retrieve the title from the video metadata - Adjusted autoplay configuration - Modified the layout The original source code is available on: https://github.com/gohugoio/hugo/tpl/tplimpl/embedded/templates/shortcodes/youtube.html https://github.com/gohugoio/hugo/tpl/tplimpl/embedded/templates/shortcodes/vimeo.html Copyright 2022 The Hugo Authors. Licensed under the Apache License, Version 2.0. */}} {{ $error := false }} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "video" "args" . "group" "partial")}} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "assets/video.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File )}} {{ $error = $args.err }} {{ end }} {{/* Initialize local arguments */}} {{- $title := $args.title -}} {{- $provider := or $args.host $args.provider }} {{- $account := $args.account }} {{ if not $account }} {{ with index $args.page.Site.Params.videos $provider }} {{ with index . "account" }}{{ $account = . }}{{ end }} {{ end }} {{ end }} {{- $pc := "" -}} {{- if eq $provider "youtube" }} {{- $pc = $args.page.Site.Config.Privacy.YouTube -}} {{- else if eq $provider "vimeo" }} {{- $pc = $args.page.Site.Config.Privacy.Vimeo -}} {{- end -}} {{- $id := or $args.mediaId $args.id -}} {{ if not $id }} {{- errorf "partial [assets/video.html] - Missing media ID" -}} {{ $error = true }} {{ end }} {{ if and (eq $provider "youtube") ($pc.Disable) }} {{- errorf "partial [assets/video.html] - YouTube video disabled in site's privacy settings" -}} {{ $error = true }} {{ else if and (eq $provider "vimeo") ($pc.Disable) }} {{- errorf "partial [assets/video.html] - Vimeo video disabled in site's privacy settings" -}} {{ $error = true }} {{ end }} {{ $queryArgs := or $args.queryArgs $args.options }} {{ $origin := $args.position }} {{ if not $origin }}{{ with $args.page.File }}{{ $origin = $args.Path }}{{ end }}{{ end }} {{/* Main code */}} {{ if not $error -}} {{ if eq $provider "youtube" }} {{- $host := cond $pc.PrivacyEnhanced "www.youtube-nocookie.com" "www.youtube.com" -}} {{ $url := printf "https://%s/embed/%s?origin=%s" $host $id $args.page.Site.BaseURL }} {{ $api := printf "https://www.youtube.com/oembed?format=json&url=%s" (printf "https://www.youtube.com/watch?v=%s" $id) }} {{ $padding := "56.25%" }} {{ with try (resources.GetRemote $api) }} {{ with .Err }} {{ errorf "Unable to parse video metadata '%q': %s\n %s" $api $origin . }} {{ else }} {{ $data := .Value | transform.Unmarshal }} {{ if $args.autotitle }}{{ with $data.title }}{{ $title = . }}{{ end }}{{ end }} {{ if and $data.height $data.width }}{{ $padding = printf "%.2f%%" (mul (div $data.height $data.width) 100) }}{{ end }} {{ end }} {{ else }} {{ errorf "Unable to get video metadata '%q': %s" $api $origin }} {{ end }}
    {{ else if eq $provider "vimeo" }} {{ $url := printf "https://player.vimeo.com/video/%s" $id }} {{ $params := "" }} {{ if $args.autoplay }}{{ $params = print $params "&autoplay=1&muted=1" }}{{ end }} {{ if $pc.EnableDNT }}{{ $params = print $params "&dnt=1" }}{{ end }} {{ $params = strings.TrimPrefix "&" $params }} {{ with $params }}{{ $url = printf "%s?%s" $url . }}{{ end }} {{ $padding := "56.25%" }} {{- $dnt := cond $pc.EnableDNT 1 0 -}} {{- $query := querify "url" $url "dnt" $dnt -}} {{- $api := printf "https://vimeo.com/api/oembed.json?%s" $query -}} {{- with try (resources.GetRemote $api) -}} {{ with .Err }} {{ errorf "Unable to parse video metadata '%q': %s\n %s" $api $origin . }} {{ else }} {{ $data := .Value | transform.Unmarshal }} {{ if $args.autotitle }}{{ with $data.title }}{{ $title = . }}{{ end }}{{ end }} {{ if and $data.height $data.width }}{{ $padding = printf "%.2f%%" (mul (div $data.height $data.width) 100) }}{{ end }} {{ end }} {{- end -}}
    {{ else if eq $provider "cloudinary" }} {{ if not $account }} {{ errorf "Missing account name for Cloudinary video '%s': %s" $id $origin }} {{ end }} {{ $url := printf "https://player.cloudinary.com/embed/?cloud_name=%s&public_id=%s" $account $id }} {{ $params := "" }} {{ if $args.autoplay }}{{ $params = print $params "&player[autoplay]=true&player[muted]=true" }}{{ end }} {{ $codecs := slice }} {{ with index site.Params "dam" }}{{ with index . "videoCodecs" }}{{ $codecs = . }}{{ end }}{{ end }} {{ range $k, $v := $codecs }} {{ $params = printf "%s&source[source_types][%d]=%s" $params $k (urlquery $v) }} {{ end }} {{ if gt (len $codecs) 0 }} {{ $params = print $params "&source[transformation][1][quality]=auto" }} {{ end }} {{ with $queryArgs }}{{ $params = print $params "&" . }}{{ end }} {{ $params = strings.TrimLeft "?&" $params }} {{ with $params }}{{ $url = print $url "&" . }}{{ end }} {{ $padding := "56.25%" }} {{ $thumbnail := partial "utilities/URLJoin.html" (dict "base" (path.Dir $id) "path" (printf "%s.jpg" (path.BaseName $id))) }} {{ $metadata := partial "assets/helpers/image-dimension.html" (dict "page" $args.page "src" (printf "https://res.cloudinary.com/%s/video/upload/%s" $account (path.Clean $thumbnail)) "ratio" $args.ratio "imageset" false ) }} {{ $height := index $metadata "height" }} {{ $width := index $metadata "width" }} {{ if and $height $width }} {{ $padding := printf "%.2f%%" (mul (div (float $height) $width) 100) }} {{ if not $title }}{{ $title = printf "Cloudinary video '%s'" (path.BaseName $id) }}{{ end }}
    {{ else }} {{ errorf "Cannot retrieve metadata of Cloudinary video '%s' with account '%s': %s" $id $account $origin }} {{ end }} {{ else }} {{ warnf "partial [assets/video.html] - Unsupported video provider: %s" $provider }} {{ end }} {{ end -}} ================================================ FILE: layouts/_partials/footer/footer.html ================================================
    {{- $copyright := printf "%s © %s %s %s." (T "copyright") (dateFormat "2006" now) .Site.Title (T "rights") }} {{ cond (gt (len .Site.Copyright) 0) .Site.Copyright $copyright }} {{ .Site.Params.footer.license | safeHTML }} | {{ if .Site.Params.main.endorse }} {{ $link := partial "assets/link.html" (dict "href" (index site.Params.links "hinode") "text" "Hinode" "class" "link-bg-footer" "page" .Page ) }} {{ T "poweredBy" $link | safeHTML }} {{ end }}
    ================================================ FILE: layouts/_partials/footer/scripts.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{- $error := false -}} {{/* Define inline partials */}} {{- define "_partials/inline/match.html" -}} {{- $result := "" -}} {{- $matches := slice -}} {{- if gt (len .modules) 0 -}} {{- range .modules -}} {{- $matches = $matches | append (printf "js/modules/%s/**.*js" .) -}} {{- end -}} {{- $result = printf "{%s}" (delimit $matches ",") -}} {{- end -}} {{- return $result -}} {{- end -}} {{- define "_partials/inline/bundle-script.html" -}} {{- $page := .page -}} {{- $match := .match -}} {{- $destination := .destination -}} {{- $cat := .cat -}} {{- $localize := .localize -}} {{- $modules := .modules -}} {{- $skipTemplate := .skipTemplate -}} {{- $enableTemplate := .enableTemplate }} {{- $absoluteURL := .absoluteURL -}} {{- $state := cond (ne .state "immediate") .state "" -}} {{- if and $cat (ne $cat "other") -}} {{- $destination = path.Join (path.Dir $destination) (printf "%s-%s%s" (path.BaseName $destination) $cat (path.Ext $destination)) -}} {{- end -}} {{- if $localize -}} {{- $destination = path.Join (path.Dir $destination) (printf "%s.%s%s" (path.BaseName $destination) $page.Language.Lang (path.Ext $destination)) -}} {{- end -}} {{- $bundle := partialCached "utilities/bundlev2.html" (dict "page" $page "match" $match "filename" $destination "modules" $modules "basepath" "js/modules" "all" true "skip-template" $skipTemplate "enable-template" $enableTemplate "debugging" site.Params.debugging.showJS ) $destination (delimit $modules ",") -}} {{- $js := $bundle.bundle -}} {{- $jsmod := $bundle.module -}} {{/* Strip js and Hugo comments then trim whitespace to detect whether the bundle contains actual code. A bundle that renders to comments only would otherwise produce a fingerprint of empty content while hugo server serves the unminified comment, causing an SRI/CSP integrity mismatch. */}} {{- $jsCode := $js.Content | replaceRE `(?m)//[^\n]*` "" | replaceRE `(?s)/\*.*?\*/` "" | strings.TrimSpace -}} {{- if gt (len $jsCode) 0 -}} {{- $integrity := "" -}} {{- if hugo.IsProduction -}} {{- $js = $js | minify | fingerprint -}} {{- $integrity = $js.Data.Integrity -}} {{- end -}} {{- partial "templates/script.html" (dict "link" (cond $absoluteURL $js.Permalink $js.RelPermalink) "category" $cat "state" $state "integrity" $integrity ) -}} {{- end -}} {{- $jsmodCode := $jsmod.Content | replaceRE `(?m)//[^\n]*` "" | replaceRE `(?s)/\*.*?\*/` "" | strings.TrimSpace -}} {{- if gt (len $jsmodCode) 0 -}} {{- $integrity := "" -}} {{- if hugo.IsProduction -}} {{- $jsmod = $jsmod | minify | fingerprint -}} {{- $integrity = $jsmod.Data.Integrity -}} {{- end -}} {{- partial "templates/script.html" (dict "link" (cond $absoluteURL $jsmod.Permalink $jsmod.RelPermalink) "category" $cat "state" $state "integrity" $integrity "script-type" "module" ) -}} {{- end -}} {{- end -}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "scripts" "args" .) -}} {{- if $args.err -}} {{- partial "utilities/LogErr.html" (dict "partial" "footer/scripts.html" "msg" "Invalid arguments" "details" $args.errmsg "file" page.File )}} {{- $error = true -}} {{- end -}} {{/* Initialize local arguments */}} {{- $patterns := dict "other" "js/critical/*.*js" "functional" "js/critical/functional/**.*js" "analytics" "js/critical/analytics/**.*js" "performance" "js/critical/performance/**.*js" "advertisement" "js/critical/advertisement/**.*js" "core" "{js/*.*js,js/vendor/**.*js}" }} {{- $absoluteURL := site.Params.main.canonifyAssetsURLs | default false -}} {{- $state := "immediate" -}} {{- $config := $args.page.Scratch.Get "modules" -}} {{- $page_modules := slice -}} {{- if reflect.IsMap $args.page.Params.modules -}} {{- $page_modules = $args.page.Params.modules -}} {{- else -}} {{- $page_modules = $page_modules | append $args.page.Params.modules -}} {{- end -}} {{- with $args.page.Scratch.Get "dependencies" -}}{{- $page_modules = append $page_modules . | uniq -}}{{- end -}} {{- $categories := dict "other" slice -}} {{- $modules := slice -}} {{- if eq $args.type "critical" -}} {{- $modules = $config.critical -}} {{- $categories = merge $categories (dict "functional" slice "analytics" slice "performance" slice "advertisement" slice) -}} {{- else if eq $args.type "core" -}} {{- $modules = $config.core -}} {{- else if eq $args.type "optional" -}} {{- $modules = $config.optional | intersect $page_modules -}} {{- end -}} {{- range $cat, $val := $config.categories -}} {{- $categories = merge $categories (dict $cat (intersect $val $modules)) -}} {{- end -}} {{- $localize := false -}} {{- if gt (intersect (or $config.localize slice) $modules | len) 0 }}{{ $localize = true }}{{ end -}} {{- $skipTemplate := false -}} {{- if gt (intersect (or $config.skipTemplate slice) $modules | len) 0 }}{{ $skipTemplate = true }}{{ end -}} {{/* Main code */}} {{- if not $error -}} {{/* include external scripts first */}} {{- range $mod, $cfg := $config.modules -}} {{- if in $modules $mod -}} {{- if or (index $cfg "local") (not hugo.IsServer) -}} {{- with index $cfg "url" -}} {{- partial "templates/script.html" (dict "link" . "category" (index $cfg "category") "state" (index $cfg "state")) -}} {{- end -}} {{- end -}} {{- end -}} {{- end -}} {{/* Bundle the critical and core scripts by category */}} {{- if ne $args.type "optional" -}} {{- range $cat, $val := $categories -}} {{- if or (gt ($val | len) 0) (eq $args.type "critical") -}} {{- $match := "" -}} {{- if eq $args.type "critical" -}} {{- $match = index $patterns $cat -}} {{- else if eq $cat "other" -}} {{- $match = index $patterns $args.type -}} {{- end -}} {{- partial "inline/bundle-script.html" (dict "page" $args.page "match" $match "destination" (printf "js/%s.bundle.js" $args.type) "cat" $cat "modules" $val "localize" $localize "skipTemplate" $skipTemplate "absoluteURL" $absoluteURL "state" (cond (eq $args.type "critical") "immediate" "async") )}} {{- end -}} {{- end -}} {{- else -}} {{/* Bundle the optional scripts by module name and category */}} {{- range $cat, $val := $categories -}} {{- range $val -}} {{- $modconfig := index $config.modules . -}} {{- partial "inline/bundle-script.html" (dict "page" $args.page "destination" (printf "js/%s.js" .) "cat" $cat "modules" (slice .) "localize" $modconfig.localize "skipTemplate" $modconfig.disabletemplate "enableTemplate" $modconfig.enableTemplate "absoluteURL" $absoluteURL "state" $modconfig.state )}} {{- end -}} {{- end -}} {{- end -}} {{- end -}} ================================================ FILE: layouts/_partials/footer/social.html ================================================ {{ if gt .Site.Menus.social 0 }} {{- $padding := partial "utilities/GetPadding.html" -}} {{- $tab := site.Params.main.externalLinks.tab -}}
    {{- $title := or .Site.Params.footer.socialTitle .Site.Params.social.title }} {{ if and site.Params.main.titleCase (not .Page.Params.exact) }}{{ $title = title $title }}{{ end }}
    {{ $title }}

    {{ or .Site.Params.footer.socialCaption .Site.Params.social.caption }}

    {{ range .Site.Menus.social -}} {{ if hasPrefix .Pre " {{ end -}}
    {{ end }} ================================================ FILE: layouts/_partials/footer/toast-container.html ================================================ {{/* Defines a container to stack toast messages. By default, toast messages are displayed in the bottom right of the viewport. Multiple toast messages are stacked vertically. Adjust the configuration by adjusting 'messages' in the site parameters. The following arguments are supported: "placement" Optional position of the toast messages relative to the viewport: "top-left", "top-center", "top-right", "middle-left", "middle-center", "middle-right", "bottom-left", "bottom-center", or "bottom-right" (default). */}} {{- $placement := "bottom-right" -}} {{- $position := "bottom-0 end-0" -}} {{- with site.Params.messages.placement }}{{ $placement = . }}{{ end -}} {{- $supportedPlacements := slice "top-left" "top-center" "top-right" "middle-left" "middle-center" "middle-right" "bottom-left" "bottom-center" "bottom-right" -}} {{- if not (in $supportedPlacements $placement) -}} {{- errorf "partial [footer/toast-container.html] - Invalid value for param 'placement': %s" $placement -}} {{- end -}} {{- if eq $placement "top-left" }}{{ $position = "top-0 start-0" -}} {{- else if eq $placement "top-center" }}{{ $position = "top-0 start-50 translate-middle-x" -}} {{- else if eq $placement "top-right" }}{{ $position = "top-0 end-0" -}} {{- else if eq $placement "middle-left" }}{{ $position = "top-50 start-0 translate-middle-y" -}} {{- else if eq $placement "middle-center" }}{{ $position = "top-50 start-50 translate-middle" -}} {{- else if eq $placement "middle-right" }}{{ $position = "top-50 end-0 translate-middle-y" -}} {{- else if eq $placement "bottom-left" }}{{ $position = "bottom-0 start-0" -}} {{- else if eq $placement "bottom-center" }}{{ $position = "bottom-0 start-50 translate-middle-x" -}} {{- else if eq $placement "bottom-right" }}{{ $position = "bottom-0 end-0" -}} {{- end -}}
    {{- partial "assets/toast.html" (dict "id" "toast-copied-code-message" "message" (printf "%s %s" (T "code") (T "copiedToClipboard"))) -}}
    ================================================ FILE: layouts/_partials/head/favicon.html ================================================ {{/* Source: https://davelage.com/posts/hugo-favicons/ */}} {{- $absoluteURL := site.Params.main.canonifyAssetsURLs | default false -}} {{ if .Site.Params.favicon.logo -}} {{ $favicon := resources.Get .Site.Params.favicon.logo -}} {{- if $favicon -}} {{ range $i := .Site.Params.favicon.sizes -}} {{ $image := $favicon.Resize (printf "%dx%d CatmullRom" $i $i) -}} {{ end -}} {{ $image := $favicon.Resize "180x CatmullRom" -}} {{ else }} {{- errorf "partial [head/favicon.html] - Cannot find file: %s" .Site.Params.favicon.logo -}} {{ end }} {{ end -}} ================================================ FILE: layouts/_partials/head/head.html ================================================ {{ define "head" }} {{- $version := strings.TrimSpace (partialCached "assets/version.html" . "version") -}} {{ $desc := .Page.Description | default (.Page.Content | safeHTML | truncate 150) -}} {{ hugo.Generator }} {{ partialCached "head/stylesheet-core.html" . -}} {{ $config := page.Scratch.Get "modules" }} {{ if not $config }} {{ errorf "partial [head/head.html] - Cannot initialize module configuration" }} {{ end }} {{ $page_modules := slice | append .Page.Params.modules }} {{ with .Scratch.Get "dependencies" }}{{ $page_modules = append $page_modules . | uniq }}{{ end }} {{- $modules := $config.optional | intersect $page_modules -}} {{- range $index, $mod := $modules -}} {{- $source := printf "scss/%s.scss" $mod -}} {{- $target := printf "css/%s.css" $mod -}} {{- partial "head/stylesheet.html" (dict "source" $source "target" $target "core" false "page" .) }} {{- end -}} {{- if hasPrefix (lower .Site.Params.style.themeFontPath) "http" -}} {{ else if .Site.Params.style.themeFontPreload }} {{ $fonts := slice | append .Site.Params.style.themeFontPreload }} {{ range $fonts }} {{ $font := partial "utilities/GetStaticURL" (dict "url" .) }} {{ end }} {{- end -}} {{ partial "head/seo.html" . }} {{ partialCached "head/favicon.html" . -}} {{ if gt (len .Site.Languages) 1}} {{ end }} {{ end }} ================================================ FILE: layouts/_partials/head/icons.html ================================================ {{/* Generate vector icons from asset templates. It processes all svg files in the "assets/icons" folder and replaces color references with their actual value. Color references should be defined in the provided css string as regular css variables within a root section called ":hinode-theme". For example, the following section defines a regular hex value and an rgba color code for two variables: :hinode-theme { --accordion-icon-active-color: #bf3300; --navbar-dark-color: rgba(255, 255, 255, 0.55); } Variable names are converted from kebab case to snake case to make them compatible with Hugo's variable naming convention. For example, the css variable '--accordion-icon-active-color' is available as '.accordion_icon_active_color' within the Hugo template. The processed svg files are published to the "icons" folder. The partial supports the following arguments: "css": Required css string content. */}} {{- $css := .css -}} {{- $content := findRE ":hinode-theme\\s?{[^}]+}" $css.Content -}} {{- $items := split (index $content 0) ";" -}} {{- $params := dict -}} {{- range $index, $item := $items -}} {{- $clean := trim $item "- \r\n{}" -}} {{- $clean = strings.TrimPrefix ":hinode-theme" $clean -}} {{- $clean = trim $clean "- \r\n{}" -}} {{- $clean = replace $clean "-" "_" -}} {{- with $clean -}} {{- $pair := split . ":" -}} {{- $key := trim (index $pair 0) " " -}} {{- $value := trim (index $pair 1) " " -}} {{- $params = merge $params (dict $key $value) -}} {{- end }} {{- end -}} {{ $base := partial "utilities/GetStaticURL" (dict "url" "/") }} {{- range resources.Match "icons/**.svg" -}} {{- $target := strings.TrimPrefix $base .RelPermalink -}} {{- $icon := . | resources.ExecuteAsTemplate $target $params -}} {{- $icon.Publish -}} {{- end -}} ================================================ FILE: layouts/_partials/head/opengraph.html ================================================ {{/* Copied from doks */}} {{ $paginator := $.Store.Get "paginator" }} {{ if $paginator }} {{ else -}} {{ end -}} {{ with .Site.Title -}} {{ end -}} {{ $iso8601 := "2006-01-02T15:04:05-07:00" -}} {{ if .IsPage -}} {{ if not .PublishDate.IsZero -}} {{ else if not .Date.IsZero -}} {{ end -}} {{ if not .Lastmod.IsZero -}} {{ end -}} {{ else -}} {{ if not .Date.IsZero -}} {{ end -}} {{ end -}} {{ with .Params.audio -}} {{ end -}} {{ with .Params.videos -}} {{ range . -}} {{ end -}} {{ end -}} ================================================ FILE: layouts/_partials/head/seo.html ================================================ {{/* TODO: replace scratch with dict */}} {{/* Adapted from doks */}} {{ with .Params.meta.title }} {{ $title := . }} {{ if and site.Params.main.titleCase (not $.Params.exact) }}{{ $title = title $title }}{{ end }} {{ $.Scratch.Set "title" $title -}} {{ else }} {{ $title := .Title | default .Site.Title }} {{ if and site.Params.main.titleCase (not $.Params.exact) }}{{ $title = title $title }}{{ end }} {{ $.Scratch.Set "title" $title -}} {{ end }} {{ $description := or (partial "utilities/GetDescription.html" (dict "page" . "meta" true)) .Site.Params.main.description }} {{ if gt (strings.RuneCount $description) 150 }} {{ $description = print (substr $description 0 150) "..." }} {{ end }} {{ $.Scratch.Set "description" $description -}} {{- $thumbnail := "" -}} {{ if reflect.IsMap .Params.Thumbnail }}{{ $thumbnail = .Params.Thumbnail.url }}{{ else }}{{ $thumbnail = .Params.Thumbnail }}{{ end }} {{ if $thumbnail -}} {{ $imgURL := index (partial "assets/helpers/image-dimension.html" (dict "src" $thumbnail "image-width" 1280 "image-height" 640 "page" .)) "target" }} {{ $.Scratch.Set "thumbnail" ($imgURL | absURL) -}} {{ else -}} {{ with .Site.Params.schema.image.url -}} {{ $.Scratch.Set "thumbnail" (. | absURL) -}} {{ else -}} {{ $images := $.Resources.ByType "image" -}} {{ $featured := $images.GetMatch "*feature*" -}} {{ if not $featured -}} {{ $featured = $images.GetMatch "{*cover*,*thumbnail*}" -}} {{ end -}} {{ with $featured -}} {{ $.Scratch.Set "thumbnail" $featured.Permalink -}} {{ else -}} {{ with $.Site.Params.opengraph.images -}} {{ $.Scratch.Set "thumbnail" (index . 0 | absURL) -}} {{ end -}} {{ end -}} {{ end -}} {{ end -}} {{ if eq .Kind "404" -}} {{ else }} {{ with or .Params.robots .Params.meta.robots .Site.Params.meta.robots -}} {{ else -}} {{ end -}} {{ end -}} {{ if .IsHome -}} {{ .Site.Title }} {{ if .Site.Params.head.tagline }} {{ .Site.Params.main.separator }} {{ .Site.Params.head.tagline }}{{ end }} {{ else -}} {{ .Title }} {{ .Site.Params.main.separator }} {{ .Site.Title }} {{ end -}} {{ partial "head/opengraph.html" . }} {{ partial "head/twitter_cards.html" . }} {{ range .AlternativeOutputFormats }} {{ printf "" .Rel .MediaType.Type .Permalink | safeHTML }} {{ end }} {{ partial "head/structured-data.html" . }} ================================================ FILE: layouts/_partials/head/structured-data.html ================================================ {{/* Copied from doks */}} {{ $baseURL := "/" | absURL -}} {{ $dot := . -}} {{ $dot.Scratch.Set "path" "" -}} {{ $dot.Scratch.Set "breadcrumb" slice -}} {{ $url := replace .Permalink ( printf "%s" .Site.BaseURL) "" -}} {{ $.Scratch.Add "path" .Site.BaseURL -}} {{ $.Scratch.Add "breadcrumb" (slice (dict "url" .Site.BaseURL "name" "home" "position" 1 )) -}} {{ range $index, $element := split $url "/" -}} {{ $dot.Scratch.Add "path" $element -}} {{ $.Scratch.Add "path" "/" -}} {{ if ne $element "" -}} {{ $.Scratch.Add "breadcrumb" (slice (dict "url" ($.Scratch.Get "path") "name" . "position" (add $index 2))) -}} {{ end -}} {{ end -}} {{ $alt := slice .Site.Params.schema.twitter .Site.Params.schema.linkedin .Site.Params.schema.github }} ================================================ FILE: layouts/_partials/head/stylesheet-core.html ================================================ {{/* Wrapper for the stylesheet partial with default arguments. */}} {{/* Added to avoid interference with the argument of partialCached. */}} {{ partial "head/stylesheet.html" -}} ================================================ FILE: layouts/_partials/head/stylesheet.html ================================================ {{- $error := false -}} {{- $transpiler := site.Params.main.build.transpiler | default "libsass" -}} {{- $silence := slice -}} {{- $supportedTranspilers := slice "libsass" "dartsass" -}} {{- if not (in $supportedTranspilers $transpiler) -}} {{- errorf "partial [head/stylesheet.html] - Invalid value for param 'transpiler': %s" $transpiler -}} {{ $error = true }} {{- end -}} {{- if site.Params.main.build.silenceDeprecations -}} {{- $silence = (slice "import" "color-functions" "global-builtin" "if-function" "legacy-js-api") -}} {{- end -}} {{- $absoluteURL := site.Params.main.canonifyAssetsURLs | default false -}} {{- $source := .source }} {{- if not $source -}} {{- if eq $transpiler "dartsass" }}{{ $source = "scss/app-dart.scss" }}{{ else }}{{ $source = "scss/app.scss" }}{{ end -}} {{- end -}} {{- $target := .target | default "css/main.css" -}} {{- $page := .page -}} {{- $core := .core | default true -}} {{- $modules := "" -}} {{ $config := page.Scratch.Get "modules" }} {{ if not $config }} {{ errorf "partial [head/stylesheet.html] - Cannot initialize module configuration" }} {{ $error = true }} {{ end }} {{ if $core }} {{- if reflect.IsSlice $config.excludeSCSS -}} {{- $modules = complement $config.excludeSCSS (append $config.core $config.critical) -}} {{ else }} {{- $modules = append $config.core $config.critical -}} {{ end }} {{- end -}} {{ if and site.Params.style.darkModeTint (not (findRE `\d+%` site.Params.style.darkModeTint)) }} {{- errorf "partial [head/stylesheet.html] - Invalid value for site param 'style.darkModeTint': %s" site.Params.style.darkModeTint -}} {{ $error = true }} {{ end}} {{- $navbarOffset := "0rem" -}} {{- $navbarOffsetXS := "0rem" -}} {{- if site.Params.navigation.fixed }} {{ $navbarOffset = site.Params.navigation.offset | default "4rem" }} {{ $navbarOffsetXS = site.Params.navigation.offsetXS | default $navbarOffset }} {{ end }} {{- $overlayOffset := $navbarOffset -}} {{- if site.Params.navigation.overlay }}{{ $overlayOffset = "0rem" }}{{ end }} {{- $vars := dict "base-url" (page.Scratch.Get "baseURL" | default "/") "theme-font" (default "Inter" site.Params.style.themeFont) "font-size-base" (default "1rem" site.Params.style.fontSizeBase) "primary" (default "#007bff" site.Params.style.primary) "secondary" (default "#6c757d" site.Params.style.secondary) "success" (default "#198754" site.Params.style.success) "info" (default "#0dcaf0" site.Params.style.info) "warning" (default "#ffc107" site.Params.style.warning) "danger" (default "#dc3545" site.Params.style.danger) "light" (default "#f8f9fa" site.Params.style.light) "dark" (default "#212529" site.Params.style.dark) "navbar-height" (site.Params.navigation.offset | default "4rem") "navbar-offset" $navbarOffset "navbar-offset-xs" $navbarOffsetXS "navbar-size" (site.Params.navigation.size | default "md") "overlay-offset" $overlayOffset "enable-dark-mode" (printf "%t" ((default true (or site.Params.main.enableDarkMode site.Params.main.colorMode.enabled)))) "import-fonts" (printf "%t" (not (hasPrefix (lower site.Params.style.themeFontPath) "http"))) "dark-mode-shade" (default "0%" site.Params.style.darkModeShade) "dark-mode-tint" (default "0%" site.Params.style.darkModeTint) "padding-x" (default 4 site.Params.main.padding.x) "padding-y" (default 4 site.Params.main.padding.y) -}} {{- $options := (dict "transpiler" $transpiler "silenceDeprecations" $silence "targetPath" $target "enableSourceMap" (not hugo.IsProduction) "vars" $vars ) -}} {{- $bundle := partialCached "utilities/bundlev2.html" (dict "page" page "match" $source "filename" (printf "scss/bundle-%s.scss" (hash.XxHash $source)) "modules" $modules "basepath" "scss" "debugging" site.Params.debugging.showSCSS ) $source page.Language.Lang (delimit $modules ",") -}} {{- if and (gt ($bundle.bundle.Content | len) 0) (not $error) }} {{- $css := $bundle.bundle | resources.ExecuteAsTemplate $target . | toCSS $options -}} {{ if $core }} {{- partialCached "head/icons.html" (dict "css" $css) ($css.Content | md5) -}} {{ end }} {{- if site.Params.style.purge -}} {{- $post_options := dict "config" "config" "noMap" hugo.IsProduction -}} {{- $css = $css | css.PostCSS $post_options -}} {{- end -}} {{- if not hugo.IsProduction -}} {{- else -}} {{- $css = $css | minify | fingerprint | resources.PostProcess -}} {{- end -}} {{- end -}} ================================================ FILE: layouts/_partials/head/twitter_cards.html ================================================ {{/* Copied from doks */}} {{ with .Site.Params.twitterSite }}{{ end }} {{ with .Site.Params.twitterCreator }}{{ end }} ================================================ FILE: layouts/_partials/page/articles.html ================================================ {{/* Add default hero and articles for list pages */}} {{- $padding := partial "utilities/GetPadding.html" -}} {{/* Render basic header for list page */}} {{ if .Site.Params.navigation.breadcrumb }} {{ partial "assets/breadcrumb.html" (dict "page" .) }} {{ end }} {{ partial "assets/section-title.html" (dict "heading" (dict "title" .Title "content" .Description "align" "start" ) "use-title" true ) }} {{/* Init the card styling */}} {{ $articlesParams := $.Scratch.Get "articlesParams" }} {{ $sort := "date" }} {{ $reverse := true }} {{ $class := "border-0 h-100" }} {{ $cardPadding := 0 }} {{ $headerStyle := "full" }} {{ $bodyStyle := "full" }} {{ $footerStyle := "none" }} {{ $iconStyle := "" }} {{ if reflect.IsMap $articlesParams }} {{ with index $articlesParams "sort" }}{{ $sort = . }}{{ end }} {{ if isset $articlesParams "reverse" }}{{ $reverse = index $articlesParams "reverse" }}{{ end }} {{ with index $articlesParams "class" }}{{ $class = . }}{{ end }} {{ with index $articlesParams "padding" }}{{ $cardPadding = . }}{{ end }} {{ with index $articlesParams "header-style" }}{{ $headerStyle = . }}{{ end }} {{ with index $articlesParams "body-style" }}{{ $bodyStyle = . }}{{ end }} {{ with index $articlesParams "footer-style" }}{{ $footerStyle = . }}{{ end }} {{ with index $articlesParams "icon-style" }}{{ $iconStyle = . }}{{ end }} {{ end }} {{/* Render paginated list of articles */}} {{ $result := partial "assets/live-pages.html" (dict "page" . "sort" $sort "reverse" $reverse) }} {{ $pages := $result.pages }} {{ if gt (len $pages) 0 }}
    {{ if site.Params.env_bookshop_live }} {{ range $pages }}
    {{ partial "assets/card.html" (dict "title" .Title "thumbnail" .Thumbnail "description" .Description "class" $class "padding" $cardPadding "header-style" $headerStyle "body-style" $bodyStyle "footer-style" $footerStyle "icon-style" $iconStyle ) }}
    {{ end }} {{ else }} {{ range (.Paginate $pages).Pages }}
    {{ partial "assets/card.html" (dict "path" .RelPermalink "class" $class "padding" $cardPadding "header-style" $headerStyle "body-style" $bodyStyle "footer-style" $footerStyle "icon-style" $iconStyle ) }}
    {{ end }} {{ end }}
    {{ if not site.Params.env_bookshop_live }}
    {{ partial "assets/pagination.html" (dict "page" .) }}
    {{ end }}
    {{ end }} ================================================ FILE: layouts/_partials/page/blocks.html ================================================ ================================================ FILE: layouts/_partials/page/metadata.html ================================================ {{- $metadata := .Scratch.Get "metadata" -}} {{ if ne $metadata "none" }} {{- $readingTime := (index site.Params.pages "readingTime") | default true -}} {{- $wordCount := (index site.Params.pages "wordCount") | default true -}} {{ if .Date }} {{ $lastmodstr := (partial "utilities/date.html" (dict "date" .Lastmod "format" "long")) -}} {{ $datestr := (partial "utilities/date.html" (dict "date" .Date "format" "long")) -}} {{ if gt .Lastmod .Date }} {{ $lastmodstr | i18n "lastModified" }} {{ else }} {{ $datestr | i18n "postedOnDate" -}} {{ end }} {{ if or $readingTime $wordCount }}•{{ end }} {{ end }} {{- if $readingTime }} {{ (math.Max .ReadingTime 1) | lang.FormatNumber 0 }} {{ i18n "minutesShort" }} {{ i18n "read" }} {{ if $wordCount }}•{{ end }} {{ end }} {{- if $wordCount }}{{ .WordCount | lang.FormatNumber 0 }} {{ i18n "words" }}{{ end }} {{ end }} ================================================ FILE: layouts/_partials/page/navbar-extra.html ================================================ {{- /* Default empty slot — override in your site to inject content into the navbar collapse section. */ -}} ================================================ FILE: layouts/_partials/page/navigation.html ================================================ {{/* Render previous / next navigation */}} {{- $pageNavPrev := partial "utilities/GetThemeIcon.html" (dict "id" "pageNavPrev" "default" "fas arrow-left") -}} {{- $pageNavNext := partial "utilities/GetThemeIcon.html" (dict "id" "pageNavNext" "default" "fas arrow-right") -}} {{/* Read the section's configuration to get the reverse setting */}} {{- $sectionPage := .CurrentSection -}} {{- $reverseParam := false -}} {{- with $sectionPage -}} {{- range .Params.content_blocks -}} {{- if eq ._bookshop_name "articles" -}} {{- with .input.reverse -}} {{- $reverseParam = . -}} {{- end -}} {{- end -}} {{- end -}} {{- end -}} {{- $result := partial "assets/live-pages.html" (dict "section" .CurrentSection.Section "sort" "title" "reverse" $reverseParam) -}} {{- $pages := $result.pages -}} {{/* Hugo's .Prev/.Next have inverted semantics - they always need to be swapped */}} {{/* Regardless of sort direction, .Next goes to earlier page, .Prev goes to later page */}} {{- $prevPage := "" -}} {{- $nextPage := "" -}} {{ if eq (printf "%T" $pages) "page.Pages" }} {{- $prevPage = $pages.Next . -}} {{- $nextPage = $pages.Prev . -}} {{ end }}
    ================================================ FILE: layouts/_partials/page/sharing.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize global arguments */}} {{- $sharing := $.Scratch.Get "sharing" -}} {{/* Main code */}} {{- if $sharing -}} {{- $order := "asc" -}} {{- $list := .Site.Params.sharing.providers -}} {{- if .Site.Params.sharing.reverse }}{{ $order = "desc" }}{{ else }}{{ $order = "asc" }}{{ end -}} {{- $sort := .Site.Params.sharing.sort | default "weight" -}} {{- $list = sort $list $sort $order -}} {{- $download := partial "utilities/GetTargetPath.html" (dict "path" .Params.download "page" .) -}} {{- if and $download (not (fileExists (path.Join "static" $download))) -}} {{- errorf "Cannot find download file for page '%s': %s" .File.Path $download -}} {{- end -}} {{- range $index, $item := $list -}} {{- $url := $item.url -}} {{- $url = replace $url "{url}" $.Permalink -}} {{- $url = replace $url "{title}" (urlquery $.Title) -}} {{- $url = $url | safeURL -}} {{- $target := "" -}} {{- $clipboard := "" -}} {{- if .clipboard -}} {{- $target = (printf "toast-message-%s-%d" (anchorize $item.name) $index ) -}} {{- $clipboard = $url -}} {{- $url = "" -}} {{- partial "assets/toast.html" (dict "id" $target "message" (printf "%s %s" (T "link") (T "copiedToClipboard"))) -}} {{- end -}} {{ partial "assets/button.html" (dict "toast-id" $target "clipboard" $clipboard "href" $url "icon" $item.icon "icon-class" "fa-fw" "class" "btn-social p-0" "label" (T "shareLink" $item.name) "spacing" false ) }} {{- end -}} {{ if .Site.Params.sharing.webshare }} {{ $attr := dict "data-sharing-title" .Title "data-sharing-description" .Description "data-sharing-url" .Permalink }} {{- with index site.Params.sharing "webshare-icon" -}} {{- partial "utilities/LogWarn.html" (dict "partial" "page/sharing.html" "warnid" "warn-deprecated-icons" "msg" "Deprecated icon params detected; migrate to the [icons] section in params.toml" "details" (slice "Replace 'sharing.webshare-icon' with 'icons.sharingWebshare'") ) -}} {{- end -}} {{- $icon := partial "utilities/GetThemeIcon.html" (dict "id" "sharingWebshare" "alias" (index site.Params.sharing "webshare-icon") "default" "fas share-nodes") -}} {{ partial "assets/button.html" (dict "href" "" "icon" $icon "icon-class" "fa-fw" "class" "btn-social p-0" "attributes" $attr "label" (T "shareLink" (T "shareSystem")) "spacing" false ) }} {{- end -}} {{ with $download }} {{ $label := (T "download" ) }} {{ $lang := strings.TrimPrefix "." (path.Ext (path.BaseName .)) }} {{ if and $lang (ne site.Language.Lang $lang) }} {{ range site.Languages }} {{ if eq .LanguageCode $lang }} {{ $label = printf "%s (%s)" (T "download") (T (printf "lang_%s" .LanguageCode)) }} {{ end }} {{ end }} {{ end }} {{ $attr := dict "download" (path.Base .) }} {{- $downloadIcon := partial "utilities/GetThemeIcon.html" (dict "id" "downloadIcon" "default" "fas download") -}} {{ partial "assets/button.html" (dict "href" . "icon" $downloadIcon "icon-class" "fa-fw" "label" $label "class" "btn-social p-0" "attributes" $attr "spacing" false ) }} {{- end -}} {{- end -}} ================================================ FILE: layouts/_partials/page/sidebar-offcanvas.html ================================================ {{- $section := .section -}} {{- $raw := .raw -}} {{ with $raw }}
    {{ strings.FirstUpper $section }}
    {{ . | safeHTML }}
    {{ end }} ================================================ FILE: layouts/_partials/page/sidebar.html ================================================ {{- $menu := .Scratch.Get "sidebar" -}} {{- $version := .Scratch.Get "version" -}} {{ if $menu }} {{ partial "assets/sidebar.html" (dict "page" . "menu" $menu "version" $version) }} {{ end -}} ================================================ FILE: layouts/_partials/page/tags.html ================================================ {{- if gt (len (.GetTerms "tags")) 0 -}}
    {{ range (.GetTerms "tags") -}} {{- $url := .Page.RelPermalink -}} {{ partial "assets/button.html" (dict "href" $url "title" .LinkTitle "color" "light" "button-size" "sm") }} {{ end -}}
    {{ range (.GetTerms "tags") -}} {{- $url := .Page.RelPermalink -}} {{ partial "assets/button.html" (dict "href" $url "title" .LinkTitle "color" "primary" "button-size" "sm" "outline" "true") }} {{ end -}}
    {{- end -}} ================================================ FILE: layouts/_partials/page/taxonomy-list.html ================================================ {{ range $.Site.Taxonomies.tags.ByCount }} {{- $title := .Page.Title }} {{ if and site.Params.main.titleCase (not $.Page.Params.exact) }}{{ $title = title $title }}{{ end }} {{ end }}
    {{ .Count }} {{ if gt .Count 1 }} {{ T "articles" }} {{ else }} {{ T "article" }} {{ end }} {{ $title | .Page.RenderString }}
    {{ if eq $.Site.Taxonomies.tags 0 }}

    {{- T "emptyTags" }}.

    {{ end }} ================================================ FILE: layouts/_partials/page/taxonomy-tag.html ================================================ {{- $breakpoint := $.Scratch.Get "breakpoint" -}} {{ $dateFormat := default "Jan 2" (index .Site.Params "date_format") }} {{ $.Scratch.Set "lastYear" ""}} {{ range .Pages.ByDate.Reverse }} {{ $year := .Date.Year }} {{ $lastYear := $.Scratch.Get "lastYear"}} {{- $title := .Title }} {{ if and site.Params.main.titleCase (not $.Page.Params.exact) }}{{ $title = title $title }}{{ end }}
    {{ with .Date }} {{ else }} - {{ end }}
    {{ if ne $year $lastYear }}

    {{ $year }}

    {{ $.Scratch.Set "lastYear" $year }} {{ end }} {{ if .Draft }}{{ T "draft" | upper }}: {{ end }}{{ $title | .Page.RenderString }}
    {{ end }} ================================================ FILE: layouts/_partials/page/thumbnail.html ================================================ {{- $page := .page -}} {{- $wrapper := printf "img-wrap" -}} {{- with .wrapper }}{{ $wrapper = printf "img-wrap %s" . }}{{ end -}} {{ $class := "rounded" }} {{ with .class }}{{ $class = . }}{{ end }} {{- $ratio := .ratio | default (site.Params.thumbnails.ratio | default "21x9") -}} {{- $thumbnail := "" -}} {{- $anchor := "" -}} {{- $credits := "" -}} {{ $figclass := .figclass }} {{- if reflect.IsMap $page.Params.Thumbnail -}} {{- $thumbnail = $page.Params.Thumbnail.url -}} {{- $anchor = $page.Params.Thumbnail.anchor }} {{- $author := "" -}} {{- if and $page.Params.Thumbnail.authorURL "text" $page.Params.Thumbnail.author }} {{- $author = partial "assets/link.html" (dict "href" $page.Params.Thumbnail.authorURL "text" $page.Params.Thumbnail.author "page" $page) -}} {{- else if $page.Params.Thumbnail.author }} {{- $author = $page.Params.Thumbnail.author -}} {{- end -}} {{- $origin := "" -}} {{- if and $page.Params.Thumbnail.originURL "text" $page.Params.Thumbnail.origin }} {{- $origin = partial "assets/link.html" (dict "href" $page.Params.Thumbnail.originURL "text" $page.Params.Thumbnail.origin "page" $page) -}} {{- else if $page.Params.Thumbnail.origin }} {{- $origin = $page.Params.Thumbnail.origin -}} {{- end }} {{- if and $author $origin }} {{ $credits = printf (T "photoFull") $author $origin }} {{ else if $author }} {{ $credits = T "photoShort" $author }} {{ end }} {{ else }} {{- $thumbnail = $page.Params.Thumbnail -}} {{- end -}} {{ if $thumbnail -}} {{- partial "assets/image.html" (dict "src" $thumbnail "anchor" $anchor "ratio" $ratio "wrapper" $wrapper "class" $class "title" $page.Params.title "caption" $credits "figclass" $figclass "priority" "high" ) -}} {{ end -}} ================================================ FILE: layouts/_partials/templates/script.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "script" "args" .) -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "templates/script.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File ) -}} {{- end -}} {{/* Initialize local arguments */}} {{- $category := cond (ne $args.category "other") $args.category "" -}} {{/* Main code */}} {{- if not $args.err -}} {{- end -}} ================================================ FILE: layouts/_partials/utilities/AddModule.html ================================================ {{ with .module }} {{- $dependencies := page.Scratch.Get "dependencies" -}} {{- if reflect.IsSlice $dependencies -}} {{- $dependencies = complement $dependencies (slice .) -}} {{ else }} {{- $dependencies = slice . -}} {{ end }} {{- page.Scratch.Set "dependencies" $dependencies -}} {{ end }} ================================================ FILE: layouts/_partials/utilities/GetBackgroundStyle.html ================================================ {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "background" "args" .) }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "utilities/GetBackgroundStyle.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File )}} {{ end }} {{ $style := $args.class }} {{ if and (not $args.err) $args.background }} {{ $background := "" }} {{ $subtle := false }} {{ if reflect.IsMap $args.background }} {{ $background = $args.background.color }} {{ $subtle = $args.background.subtle }} {{ else }} {{ $background = $args.background }} {{ end }} {{ if and $subtle (not (hasPrefix $background "body")) }} {{- $style = printf "%s bg-%s-subtle" (or $style "") $background -}} {{ else if $background }} {{- $style = printf "%s bg-%s" (or $style "") $background -}} {{ end }} {{ end }} {{ return (trim $style " ") }} ================================================ FILE: layouts/_partials/utilities/GetIllustration.html ================================================ {{- $item := .item -}} {{- $illustration := "" -}} {{- $style := "img-wrap mx-auto mx-md-0" -}} {{- $size := .size | default "col-12 col-sm-4 col-lg-12" -}} {{ if $item.Params.icon }} {{- $icon := (or (and (reflect.IsMap $item.Params.Icon) $item.Params.Icon.url) $item.Params.Icon) -}} {{- $mode := and (reflect.IsMap $item.Params.Icon) $item.Params.Icon.mode -}} {{ if eq (lower (path.Ext $icon)) ".json" }} {{ $illustration = partial "assets/animation.html" (dict "data" $icon "mode" $mode "loop" false "hover" true "class" (printf "mx-auto text-center %s" $size)) }} {{ else }} {{ $illustration = partial "assets/icon.html" (dict "icon" "mode" $mode $icon "wrapper" "mx-auto text-center")}} {{ end }} {{ else }} {{- $thumbnail := "" -}} {{ if reflect.IsMap $item.Params.Thumbnail }}{{ $thumbnail = $item.Params.Thumbnail.url }}{{ else }}{{ $thumbnail = $item.Params.Thumbnail }}{{ end }} {{- if $thumbnail }} {{ $illustration = partial "assets/image.html" (dict "src" $thumbnail "ratio" "16x9" "wrapper" $style "inner" "rounded" "title" $item.Site.Title ) }} {{ end }} {{ end }} {{ return $illustration }} ================================================ FILE: layouts/_partials/utilities/GetIncludeTOC.html ================================================ {{- $includeToc := false -}} {{- if .Site.Params.navigation.toc -}} {{- $includeToc = true -}} {{- if isset .Params "includeToc" -}} {{- $includeToc = .Params.includeToc -}} {{- else -}} {{- with (index site.Params.pages .Type) -}} {{- if isset . "includetoc" -}} {{- $includeToc = index . "includetoc" -}} {{- if ne (printf "%T" $includeToc) "bool" -}} {{- errorf "Expected bool value in site parameters: pages.%s.includeToc" $.Type -}} {{- end -}} {{- end -}} {{- end -}} {{- end -}} {{- end -}} {{- return $includeToc -}} ================================================ FILE: layouts/_partials/utilities/GetLink.html ================================================ {{ $error := false -}} {{ $msg := "" -}} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "link" "args" . "group" "partial") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "utilities/GetLink.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File )}} {{ $error = $args.err }} {{ end }} {{- $destination := strings.TrimPrefix (strings.TrimSuffix "/" site.BaseURL) $args.href -}} {{- $isExternal := or (ne (urls.Parse (absURL $destination)).Host (urls.Parse site.BaseURL).Host) $args.external -}} {{- $anchor := "" -}} {{- if not $isExternal -}} {{- if strings.Contains $destination "#" }} {{ $segments := split $destination "#" }} {{- if ne (len $segments) 2 }} {{ $msg = printf "Malformed path, expected one anchor '#' only: %s" $destination}} {{ $error = true }} {{ else }} {{- $destination = index $segments 0 -}} {{- $anchor = index $segments 1 -}} {{ end }} {{ end }} {{ if $destination }} {{ $ref := partial "utilities/GetPage.html" (dict "url" $destination "page" $args.page) }} {{- if not $ref -}} {{- $msg = printf "Cannot find page: %s" $destination -}} {{- $error = true -}} {{- else -}} {{- $destination = $ref.RelPermalink -}} {{- with $anchor }}{{ $destination = printf "%s#%s" (strings.TrimSuffix "/" $destination) . -}}{{ end -}} {{- end -}} {{ else }} {{ $destination = printf "#%s" $anchor }} {{ end }} {{- end -}} {{ return (dict "href" $destination "error" $error "msg" $msg) }} ================================================ FILE: layouts/_partials/utilities/GetMetadata.html ================================================ {{- $metadata := "full" -}} {{ if isset .Params "metadata" }} {{ $metadata = .Params.metadata }} {{ else }} {{- with (index site.Params.pages .Type ) -}} {{ if isset . "metadata" }}{{ $metadata = (index . "metadata") }}{{ end }} {{- end -}} {{ end }} {{- $supportedStates := slice "full" "original" "none" -}} {{- if not (in $supportedStates $metadata) -}} {{- errorf "layout [_default/page/header.html] - Invalid value for param 'metadata': %s" $metadata -}} {{- end -}} {{ return $metadata }} ================================================ FILE: layouts/_partials/utilities/GetSharing.html ================================================ {{- $sharing := false -}} {{- if .Site.Params.sharing.enabled -}} {{- $sharing = true -}} {{ if isset .Params "sharing" }} {{ $sharing = .Params.sharing }} {{ else }} {{- with (index .Site.Params.pages .Type ) -}} {{ if isset . "sharing" }} {{ $sharing = (index . "sharing") }} {{ end }} {{- end -}} {{ end }} {{ end }} {{ return $sharing }} ================================================ FILE: layouts/_partials/utilities/InitModules.html ================================================ {{ $critical := slice }} {{ $core := slice }} {{ $optional := slice }} {{ $excludeSCSS := slice }} {{ $disableTemplate := slice }} {{ $localize := slice }} {{ $category := dict }} {{ $modules := dict }} {{ range $key, $mod := .Site.Params.modules }} {{ if reflect.IsMap $mod }} {{ $integration := index $mod "integration" }} {{ if eq $integration "critical" }} {{ $critical = $critical | append $key }} {{ else if eq $integration "core" }} {{ $core = $core | append $key }} {{ else if eq $integration "optional" }} {{ $optional = $optional | append $key }} {{ else if $integration }} {{ warnf "Unrecognized module integration setting: %s" $integration }} {{ end }} {{ if eq (index $mod "excludeSCSS") true }} {{ $excludeSCSS = $excludeSCSS | append $key }} {{ end }} {{ if eq (index $mod "disableTemplate") true }} {{ $disableTemplate = $disableTemplate | append $key }} {{ end }} {{ if eq (index $mod "localize") true }} {{ $localize = $localize | append $key }} {{ end }} {{ $categoryKey := "other" }} {{ with (index $mod "category") }}{{ $categoryKey = . }}{{ end }} {{ $cat := index $category $categoryKey | default slice }} {{ $cat = $cat | append $key}} {{ $category = merge $category (dict $categoryKey $cat) }} {{ $modules = merge $modules (dict $key $mod) }} {{ else }} {{ warnf "Unsupported module parameter: %s" $key }} {{ end }} {{ end }} {{ $modules := dict "modules" $modules "critical" $critical "core" $core "optional" $optional "excludeSCSS" $excludeSCSS "disableTemplate" $disableTemplate "localize" $localize "categories" $category }} {{- if and .IsPage (not (in $core "bootstrap")) -}} {{- errorf "Bootstrap is a required module, please add it to 'modules.core' in your site parameters" -}} {{- end -}} {{ return $modules }} ================================================ FILE: layouts/_partials/utilities/git.html ================================================ {{ with .GitInfo }} • {{ .Subject }} ({{ .AbbreviatedHash }}) {{ end -}} ================================================ FILE: layouts/_shortcodes/abbr.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $error := false }} {{/* Validate and initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "abbr" "args" .Params "named" .IsNamedParams "group" "shortcode") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/abbr.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err }} {{ end }} {{/* Initialize arguments and default values */}} {{ $entries := slice }} {{ $title := "" }} {{/* Main code */}} {{ if not $error }} {{/* Try language-specific file first */}} {{ $path := path.Join (path.Dir $args.data) (printf "%s.%s" (path.BaseName $args.data) .Page.Language.Lang) (path.Ext $args.data) }} {{ $entries = index site.Data $path }} {{/* Use exact provided path as backup */}} {{ if not $entries -}} {{ $entries = index site.Data $args.data }} {{ end }} {{ if not $entries -}} {{ errorf "Invalid abbrevation data '%s': %s" $args.data .Position -}} {{ $error = true }} {{ end -}} {{ end }} {{ if not $error }} {{ $elements := (where $entries "id" (lower $args.key)) }} {{ if gt (len $elements) 0 }} {{ $title = index (index $elements 0) "long" }} {{ end -}} {{ if not $title -}} {{ errorf "Cannot find value for '%s': %s" $args.key .Position -}} {{ $error = true }} {{ end -}} {{ end }} {{ if not $error }} {{ $args.key }} {{ end }} ================================================ FILE: layouts/_shortcodes/abbr.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "abbr" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} {{- $entries := index site.Data $args.data -}} {{- $title := "" -}} {{- with where $entries "id" (lower $args.key) -}}{{- $title = index (index . 0) "long" -}}{{- end -}} {{ $args.key }}{{ with $title }} ({{ . }}){{ end -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/accordion-item.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $error := false }} {{/* Validate and initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "accordion-item" "args" .Params "named" .IsNamedParams "group" "shortcode") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/accordion-item.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err }} {{ end }} {{ if not .Parent }} {{ errorf "Cannot use isolated accordion-item, wrap it in an accordion: %s" .Position -}} {{ $error = true }} {{ end }} {{/* Initialize arguments and default values */}} {{- $id := .Ordinal -}} {{ $parent := "" }} {{ if not $error }} {{- $parent = printf "accordion-%d" .Parent.Ordinal -}} {{- with (.Parent.Get "id") -}} {{- $parent = . -}} {{- end -}} {{- end -}} {{ $body := trim .Inner " \r\n" -}} {{ if not $body -}} {{ if .Parent }} {{ errorf "Missing inner element text: %s" .Parent.Position -}} {{ else }} {{ errorf "Missing inner element text: %s" .Position -}} {{ end }} {{ $error = true }} {{ end -}} {{/* Main code */}} {{ $show := false -}} {{ if not $error }}
    {{- with (or $args.title $args.header) -}}
    {{- end -}}
    {{ $body | .Page.RenderString | safeHTML }}
    {{ end }} ================================================ FILE: layouts/_shortcodes/accordion-item.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "accordion-item" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} {{- $title := or $args.title $args.header -}} {{ with $title }}### {{ . }} {{ end -}} {{ trim .Inner " \r\n" }} {{- end -}} ================================================ FILE: layouts/_shortcodes/accordion.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Validate and initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "accordion" "args" .Params "named" .IsNamedParams "group" "shortcode") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/accordion.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ end }} {{/* Initialize arguments and default values */}} {{- $id := $args.id | default (printf "accordion-%d" .Ordinal) -}} {{- $body := chomp .Inner -}} {{- if $args.alwaysOpen -}} {{- $pattern := printf "data-bs-parent=\"#%s\"" $id -}} {{- $body = (replace .Inner $pattern "") }} {{- end -}} {{/* Main code */}} {{ if not $args.error }}
    {{- $body | safeHTML -}}
    {{ end }} ================================================ FILE: layouts/_shortcodes/accordion.md ================================================ {{ .Inner -}} ================================================ FILE: layouts/_shortcodes/alert.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $error := false }} {{/* Validate and initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "alert" "args" .Params "named" .IsNamedParams "group" "shortcode") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/alert.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err }} {{ end }} {{/* Initialize arguments and default values */}} {{ $color := $args.color -}} {{ $icon := $args.icon }} {{- $admonition := partial "utilities/GetThemeIcon.html" (dict "id" "admonition" "default" dict) -}} {{ if eq $args.alertType "danger" }} {{ $icon = ($admonition.warning | default "fas triangle-exclamation") }} {{ $color = "danger" }} {{ else if eq $args.alertType "info" }} {{ $icon = ($admonition.info | default "fas circle-info") }} {{ $color = "info" }} {{ end }} {{ with $icon }} {{ $icon = partial "assets/icon.html" (dict "icon" . "class" "fa-2x fa-fw") }} {{ end }} {{ $body := trim .Inner " \r\n" -}} {{ if not $body -}} {{ errorf "Missing inner element text: %s" .Position -}} {{ $error = true }} {{ end -}} {{/* Main code */}} {{- if not $error -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/alert.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "alert" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} {{- $body := trim .Inner " \r\n" | plainify -}} {{- $callout := "NOTE" -}} {{- if eq $args.alertType "danger" -}}{{- $callout = "WARNING" -}}{{- end -}} > [!{{ $callout }}] > {{ $body }} {{- end -}} ================================================ FILE: layouts/_shortcodes/args.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{- $error := false -}} {{/* Validate and initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "args" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/args.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position ) -}} {{- $error = $args.err -}} {{- end -}} {{/* Main code */}} {{- if not $args.err -}} {{- partial "assets/args.html" (dict "page" .Page "structure" $args.structure "group" $args.group "parent" $args.parent "render-type" $args.renderType "header-level" $args.headerLevel "_default" $args.default ) -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/args.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "args" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} {{- $structDef := index site.Data.structures $args.structure -}} {{- /* Fallback: resolve bookshop-{name} from the mounted component blueprint */ -}} {{- if and (not $structDef) (strings.HasPrefix $args.structure "bookshop-") -}} {{- $compName := strings.TrimPrefix "bookshop-" $args.structure -}} {{- $blueprint := index (index (index site.Data.structures.components $compName) (printf "%s.bookshop" $compName)) "blueprint" | default dict -}} {{- if $blueprint -}} {{- $bpArgs := dict -}} {{- range $k, $v := $blueprint -}} {{- $kebab := $k | replaceRE "_" "-" -}} {{- $bpArgs = merge $bpArgs (dict $kebab nil) -}} {{- end -}} {{- $structDef = dict "arguments" $bpArgs -}} {{- end -}} {{- end -}} {{- with $structDef -}} {{- $globalArgs := ((index site.Data.structures "_arguments") | default dict).arguments | default dict -}} {{- $rows := slice -}} {{- range $key, $val := .arguments -}} {{- if and $val (reflect.IsMap $val) -}}{{- if $val.deprecated }}{{ continue }}{{ end -}}{{- end -}} {{- $g := index $globalArgs $key | default dict -}} {{- $argMap := dict -}} {{- if and $val (reflect.IsMap $val) }}{{- $argMap = $val -}}{{ end -}} {{- $merged := merge $g $argMap -}} {{- if and $args.group $merged.group (ne $merged.group $args.group) }}{{ continue }}{{ end -}} {{- $required := "" -}} {{- if not (default false $merged.optional) }}{{- $required = "yes" -}}{{ end -}} {{- $default := "" -}} {{- with $merged.default }}{{- $default = printf "`%v`" . -}}{{ end -}} {{- $comment := $merged.comment | default "" | replaceRE "\n" " " -}} {{- if $merged.options.values -}}{{- $comment = printf "%s Supported values: [`%s`]." $comment (delimit $merged.options.values "`, `") -}}{{- end -}} {{- $typeVal := $merged.type | default "string" -}} {{- if reflect.IsSlice $typeVal }}{{- $typeVal = index $typeVal 0 | default "string" -}}{{ end -}} {{- $rows = $rows | append (printf "| `%s` | %s | %s | %s | %s |" $key $typeVal $required $default $comment) -}} {{- end -}} {{- if $rows }} | Name | Type | Required | Default | Description | | --- | --- | --- | --- | --- | {{ delimit $rows "\n" }} {{- end -}} {{- end -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/badge.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Validate and initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "badge" "args" .Params "named" .IsNamedParams "group" "shortcode") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/badge.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ end }} {{/* Main code */}} {{- if not $args.err }} {{ $args.title | plainify }} {{ end -}} ================================================ FILE: layouts/_shortcodes/badge.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "badge" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} {{ $args.title | plainify -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/breadcrumb.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $error := false }} {{/* Validate and initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "breadcrumb" "args" .Params "named" .IsNamedParams "group" "shortcode") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/breadcrumb.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err }} {{ end }} {{/* Initialize arguments and default values */}} {{- $page := .Page -}} {{- if $args.path -}} {{- $page = .Site.GetPage $args.path -}} {{- if not $page -}} {{- errorf "Invalid or missing value for param 'path': %s" .Position -}} {{- $error = true -}} {{- end -}} {{- end -}} {{/* Main code */}} {{- if not $error -}} {{- partial "assets/breadcrumb.html" (dict "page" $page) -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/breadcrumb.md ================================================ {{- /* Breadcrumb is decorative — no meaningful output for LLM */ -}} ================================================ FILE: layouts/_shortcodes/button-group.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Validate and initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "button-group" "args" .Params "named" .IsNamedParams "group" "shortcode") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/button-group.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ end }} {{/* Initialize local arguments */}} {{ $label := or $args.label $args.ariaLabel }} {{ $role := or $args.ariaRole "group" }} {{ $inner := .Scratch.Get "inner" }} {{ $input := trim .Inner " \r\n" }} {{ if $input }} {{ $input = replace $input "\n" "\n " }} {{ warnf "Unexpected inner content: %s\r\n %s" .Position $input }} {{ end }} {{/* Main code */}} {{ if not $args.err }}
    {{ $inner | safeHTML }}
    {{ end }} ================================================ FILE: layouts/_shortcodes/button-group.md ================================================ {{ .Inner -}} ================================================ FILE: layouts/_shortcodes/button.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $error := false }} {{/* Validate and initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "button" "args" .Params "named" .IsNamedParams "group" "shortcode") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/button.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err }} {{ end }} {{/* Initialize arguments */}} {{ $label := or $args.label $args.ariaLabel -}} {{ $title := trim .Inner " \r\n" | .Page.RenderString -}} {{ if not (or $title $args.icon) -}} {{ errorf "Missing icon or inner element text: %s" .Position -}} {{ $error = true }} {{ end -}} {{ $href := $args.href -}} {{ if $args.relref }} {{ $href = relref . $args.relref }} {{ end }} {{ $spacing := cond .Parent false $args.spacing }} {{/* Main code */}} {{ if not $error }} {{- $output := partial "assets/button.html" (dict "link-type" (or $args.linkType $args.type) "title" $title "button-size" (or $args.buttonSize $args.size) "color" $args.color "outline" $args.outline "badge" $args.badge "label" $label "tooltip" $args.tooltip "clipboard" $args.clipboard "collapse-id" (or $args.collapseId $args.collapse) "href" $args.href "id" $args.id "button-state" (or $args.buttonState $args.state) "class" $args.class "placement" $args.placement "icon" $args.icon "icon-class" $args.iconClass "order" $args.order "justify" $args.justify "cue" $args.cue "tab" $args.tab "toast-id" (or $args.toastId $args.toast) "spacing" $spacing "_default" $args.default ) -}} {{ with $args.wrapper }} {{ $output = printf `
    %s
    ` . $output }} {{ end }} {{- if .Parent -}} {{ $current := .Parent.Scratch.Get "inner" }} {{ if $current }} {{ .Parent.Scratch.Set "inner" (print $current $output) }} {{ else }} {{ .Parent.Scratch.Set "inner" $output }} {{ end }} {{- else -}} {{ $output | safeHTML }} {{- end -}} {{ end }} ================================================ FILE: layouts/_shortcodes/button.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "button" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} {{- $title := trim .Inner " \r\n" | plainify -}} {{- $href := $args.href -}} {{- if $args.relref }}{{- $href = relref . $args.relref -}}{{- end -}} {{- if $href -}} [{{ $title }}]({{ $href }}) {{- else -}} {{ $title }} {{- end -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/card-group.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $error := false }} {{/* Validate and initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "card-group" "child" "card" "args" .Params "named" .IsNamedParams) }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/card-group.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err }} {{ end }} {{/* Initialize arguments and default values */}} {{- $cols := .Get "cols" | default "3" -}} {{- $gutter := .Get "gutter" | default "4" -}} {{- $title := .Get "title" | default "" -}} {{- $separator := .Get "separator" | default "" -}} {{- $wrapper := .Get "wrapper" | default "" -}} {{- $responsive := .Get "responsive" | default true -}} {{/* Initialize arguments passed to individual cards */}} {{- $class := .Get "class" | default "" -}} {{- $color := .Get "color" | default "" -}} {{- $padding := .Get "padding" | default 3 -}} {{- $header := .Get "header-style" | default "" -}} {{- $body := .Get "body-style" | default "" -}} {{- $footer := .Get "footer-style" | default "" -}} {{- $orientation := .Get "orientation" | default "" -}} {{- $align := .Get "align" | default "start" -}} {{- $style := .Get "icon-style" | default "" -}} {{- $subtle := .Get "subtle" | default false -}} {{- $button := .Get "button" | default false -}} {{- $linkIcon := .Get "link-icon" | default false -}} {{- $buttonType := .Get "link-type" | default "" -}} {{- $iconRounded := .Get "icon-rounded" | default false -}} {{- with .Get "header" }}{{- $header = . -}}{{- end -}} {{- with .Get "footer" }}{{- $footer = . -}}{{- end -}} {{- with .Get "style" }}{{- $style = . -}}{{- end -}} {{- with .Get "buttonType" }}{{- $buttonType = . -}}{{- end -}} {{- with .Get "iconRounded" }}{{- $iconRounded = . -}}{{- end -}} {{- $scroll := .Get "scroll" | default false -}} {{ $inner := .Scratch.Get "inner" }} {{ $input := trim .Inner " \r\n" }} {{ if $input }} {{ $input = replace $input "\n" "\n " }} {{ warnf "Unexpected inner content: %s\r\n %s" .Position $input }} {{ end }} {{/* Main code */}} {{- partial "assets/card-group.html" (dict "page" .Page "cards" $inner "cols" $cols "gutter" $gutter "title" $title "separator" $separator "wrapper" $wrapper "responsive" $responsive "class" $class "color" $color "padding" $padding "header-style" $header "body-style" $body "footer-style" $footer "orientation" $orientation "align" $align "icon-style" $style "subtle" $subtle "button" $button "link-icon" $linkIcon "link-type" $buttonType "icon-rounded" $iconRounded "scroll" $scroll "bento" $args.bento "valign" $args.valign "loading" $args.loading "_default" $args.default ) -}} ================================================ FILE: layouts/_shortcodes/card-group.md ================================================ {{ .Inner -}} ================================================ FILE: layouts/_shortcodes/card.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $error := false }} {{/* Validate and initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "card" "args" .Params "named" .IsNamedParams "group" "shortcode") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/card.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err }} {{ end }} {{/* Initialize arguments and default values */}} {{/* TODO: use initargs instead of GetArgParent */}} {{- $alt := .Get "alt" -}} {{- $class := partial "utilities/GetArgParent" (dict "page" . "arg" "class" "merge" true) -}} {{- $color := partial "utilities/GetArgParent" (dict "page" . "arg" "color") -}} {{- $description := trim .Inner " \r\n" | .Page.RenderString | safeHTML -}} {{- $footer := or (partial "utilities/GetArgParent" (dict "page" . "arg" "footer-style")) (partial "utilities/GetArgParent" (dict "page" . "arg" "footer")) -}} {{- $gutter := partial "utilities/GetArgParent" (dict "page" . "arg" "gutter") -}} {{- $body := or (partial "utilities/GetArgParent" (dict "page" . "arg" "body-style")) (partial "utilities/GetArgParent" (dict "page" . "arg" "body")) -}} {{- $header := or (partial "utilities/GetArgParent" (dict "page" . "arg" "header-style")) (partial "utilities/GetArgParent" (dict "page" . "arg" "header")) -}} {{- $icon := .Get "icon" -}} {{- $iconRounded := or (partial "utilities/GetArgParent" (dict "page" . "arg" "icon-rounded")) (partial "utilities/GetArgParent" (dict "page" . "arg" "iconRounded")) -}} {{- $align := partial "utilities/GetArgParent" (dict "page" . "arg" "align") | default "start" -}} {{- $style := or (partial "utilities/GetArgParent" (dict "page" . "arg" "icon-style")) (partial "utilities/GetArgParent" (dict "page" . "arg" "style")) -}} {{- $subtle := partial "utilities/GetArgParent" (dict "page" . "arg" "subtle") -}} {{- $loading := .Get "loading" -}} {{- $orientation := partial "utilities/GetArgParent" (dict "page" . "arg" "orientation") -}} {{- $padding := partial "utilities/GetArgParent" (dict "page" . "arg" "padding") | default 3 -}} {{- $ratio := partial "utilities/GetArgParent" (dict "page" . "arg" "ratio") -}} {{- $portrait := partial "utilities/GetArgParent" (dict "page" . "arg" "portrait") -}} {{- $page := .Page -}} {{- $path := .Get "path" -}} {{- $thumbnail := .Get "thumbnail" -}} {{- $anchor := .Get "anchor" -}} {{- $title := .Get "title" -}} {{- $button := partial "utilities/GetArgParent" (dict "page" . "arg" "button") -}} {{- $linkIcon := partial "utilities/GetArgParent" (dict "page" . "arg" "link-icon") -}} {{- $linkType := or (partial "utilities/GetArgParent" (dict "page" . "arg" "link-type")) (partial "utilities/GetArgParent" (dict "page" . "arg" "buttonType")) -}} {{- $cols := partial "utilities/GetArgParent" (dict "page" . "arg" "cols") -}} {{- $scroll := partial "utilities/GetArgParent" (dict "page" . "arg" "scroll") -}} {{- $wrapper := "" -}} {{/* Override arguments */}} {{- if $path }} {{ $page := partial "utilities/GetPage.html" (dict "url" $args.path "page" (or $args.page page)) }} {{ $validate := site.Params.main.internalLinks.validate | default true }} {{- if and $validate (not $page) }} {{- warnf "Cannot find target page '%s': %s" $path .Position -}} {{- end }} {{- end }} {{ if .Parent }} {{ $class = (printf "h-100 %s" $class) }} {{ end }} {{ if $scroll }} {{ $wrapper = printf "card-block-%d p-0" $cols }} {{ end }} {{/* Main code */}} {{ if not $error -}} {{/* Render card */}} {{- $output := partial "assets/card.html" (dict "path" $path "href" $args.href "title" $title "exact" $args.exact "class" $class "gutter" $gutter "color" $color "padding" $padding "header-style" $header "body-style" $body "footer-style" $footer "orientation" $orientation "description" $description "ratio" $ratio "portrait" $portrait "icon" $icon "icon-rounded" $iconRounded "align" $align "icon-style" $style "subtle" $subtle "scroll" $scroll "wrapper" $wrapper "thumbnail" $thumbnail "loading" $loading "anchor" $anchor "alt" $alt "button" $button "button-label" $args.buttonLabel "link-icon" $linkIcon "link-type" $linkType "_default" $args.default ) -}} {{/* Pass output to parent or current stream */}} {{ with .Parent }} {{ $current := .Scratch.Get "inner" }} {{ if $current }} {{ .Scratch.Set "inner" (print $current $output) }} {{ else }} {{ .Scratch.Set "inner" $output }} {{ end }} {{ else }} {{ print $output | safeHTML }} {{ end }} {{ end -}} ================================================ FILE: layouts/_shortcodes/card.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "card" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} {{- $title := .Get "title" -}} {{- $description := trim .Inner " \r\n" | plainify -}} {{ with $title }}**{{ . }}**{{ if $description }}: {{ end }}{{ end -}} {{- $description }} {{- end -}} ================================================ FILE: layouts/_shortcodes/carousel.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "carousel" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/carousel.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{- end -}} {{/* Initialize local arguments */}} {{- $id := $args.id | default (printf "carousel-%d" .Ordinal) -}} {{ $inner := .Scratch.Get "inner" }} {{ $input := trim .Inner " \r\n" }} {{ if $input }} {{ $input = replace $input "\n" "\n " }} {{ warnf "Unexpected inner content: %s\r\n %s" .Position $input }} {{ end }} {{ $items := len (findRE "carousel-item" $inner) -}} {{/* Main code */}} {{ if not $args.err }} {{ end }} ================================================ FILE: layouts/_shortcodes/carousel.md ================================================ {{ .Inner -}} ================================================ FILE: layouts/_shortcodes/collapse.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $error := false -}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "collapse" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/collapse.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err -}} {{- end -}} {{/* Initialize local arguments */}} {{- $body := trim .Inner " \r\n" -}} {{ if not $body -}} {{ errorf "Missing inner element text: %s" .Position -}} {{ $error = true }} {{ end -}} {{/* Main code */}} {{ if not $error }}
    {{ $body | .Page.RenderString }}
    {{ end }} ================================================ FILE: layouts/_shortcodes/collapse.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "collapse" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} {{ trim .Inner " \r\n" -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/command.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $symbols := dict "bash" (dict "prompt" "$" "contPrompt" ">" "contString" "\\") "powershell" (dict "prompt" "PS>" "contPrompt" ">>" "contString" "`") "sql" (dict "prompt" "sql>" "contPrompt" "->" "contString" "(con)") }} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "command" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/command.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{- end -}} {{/* Initialize local arguments */}} {{- $prompt := $args.prompt | default (index (index $symbols $args.shell) "prompt") -}} {{- $contPrompt := index (index $symbols $args.shell) "contPrompt" -}} {{- $contString := index (index $symbols $args.shell) "contString" -}} {{- $filter := "(out)" -}} {{- $input := trim .Inner " \t\r\n" -}} {{- if (and (eq $args.shell "bash") $args.host $args.user) -}} {{- $prompt = printf "[%s@%s] %s" $args.user $args.host $prompt -}} {{- end -}} {{/* Main code */}} {{ if not $args.err }} {{- $lines := split $input "\n" -}} {{- $prefix := "" -}} {{- $prevLine := "" -}} {{- $refined := "" -}} {{- range $line := $lines -}} {{- $line = trim $line " \t\r\n" -}} {{- if hasPrefix $line $filter -}} {{- $prefix = printf "%s" $prefix -}} {{- if eq $args.shell "sql" -}} {{- $line = printf "--%s" (strings.TrimPrefix $filter $line) -}} {{- else -}} {{- $line = printf "#%s" (strings.TrimPrefix $filter $line) -}} {{- end -}} {{- else if (strings.HasSuffix $prevLine $contString) -}} {{- $prefix = printf "%s" $prefix $contPrompt -}} {{- else -}} {{- $prefix = printf "%s" $prefix $prompt -}} {{- end -}} {{- $prevLine = $line -}} {{- if (and (eq $args.shell "sql") (strings.HasSuffix $line $contString)) -}} {{- $line = strings.TrimSuffix $contString $line -}} {{- end -}} {{- $refined = printf "%s\n%s" $refined $line -}} {{- end -}} {{- $refined := trim $refined "\r\n" -}} {{- $output := (transform.Highlight $refined $args.shell | safeHTML) -}} {{- $insert := printf "%s" $prefix -}} {{- $output := (replace $output ("" | safeHTML) $insert 1 | safeHTML) -}} {{- if eq $args.shell "sql" -}} {{- $output = (replace $output "--" "" | safeHTML) -}} {{- else -}} {{- $output = (replace $output "#" "" | safeHTML) -}} {{- $output = (replace $output "#" "" | safeHTML) -}} {{- end -}}
    {{- $output -}}
    {{ end }} ================================================ FILE: layouts/_shortcodes/command.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "command" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} {{- printf "```%s\n%s\n```" $args.shell (trim .Inner " \t\r\n") -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/docs.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. This source code adapts the original embedded shortcode as maintained by the The Bootstrap Authors. It introduces the following modifications: - Added validation of shortcode arguments - Modified the layout The original source code is available on: https://github.com/twbs/bootstrap/blob/main/site/layouts/shortcodes/scss-docs.html Copyright (c) 2011-2023 The Bootstrap Authors. Licensed under The MIT License (MIT). */}} {{ $error := false -}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "docs" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/docs.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err }} {{- end -}} {{/* Initialize local arguments */}} {{- $id := $args.id | default (printf "docs-collapse-%d" .Ordinal) -}} {{- $basePath := .Site.Params.docs.basePath -}} {{- $file := $args.file -}} {{- if hasPrefix $file "./" -}} {{- $file = path.Clean $file -}} {{- else -}} {{- $file = path.Join $basePath (path.Clean $file) -}} {{- end -}} {{- $extension := strings.TrimLeft "." (path.Ext $file) }} {{- $captureStart := "" -}} {{- $captureEnd := "" -}} {{- $supportedExtensions := slice "js" "scss" "toml" -}} {{- if in $supportedExtensions $extension -}} {{- if eq $extension "toml" }} {{- $captureStart = printf "# toml-docs-start %s" $args.name -}} {{- $captureEnd = printf "# toml-docs-end %s" $args.name -}} {{- else -}} {{- $captureStart = printf "// %s-docs-start %s" $extension $args.name -}} {{- $captureEnd = printf "// %s-docs-end %s" $extension $args.name -}} {{- end -}} {{- else -}} {{- errorf "File format not supported (line %s): %s" .Position $file -}} {{- end -}} {{/* Main code */}} {{- if not $error -}} {{- /* Check if the file exists, skip gracefully if not (e.g. local module replacement without vendor) */ -}} {{- $statResult := try (os.Stat $file) -}} {{- if $statResult.Err -}} {{- warnf "shortcodes/docs.html - Cannot find file: %q. Skipping." $file -}} {{- $error = true -}} {{- end -}} {{- end -}} {{- if not $error -}} {{- $regex := printf `%s((?:.|\n)*)%s` $captureStart $captureEnd -}} {{- $match := findRE $regex (readFile $file) -}} {{- $match = index $match 0 -}} {{- if not $match -}} {{- errorf "%s: %q: Got no matches for name=%q in file=%q!" .Position .Name $args.name $file -}} {{- end -}} {{- $match = replace $match $captureStart "" -}} {{- $match = replace $match $captureEnd "" -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/docs.md ================================================ {{ $error := false -}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "docs" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/docs.md" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err }} {{- end -}} {{/* Initialize local arguments */}} {{- $basePath := .Site.Params.docs.basePath -}} {{- $file := $args.file -}} {{- if hasPrefix $file "./" -}} {{- $file = path.Clean $file -}} {{- else -}} {{- $file = path.Join $basePath (path.Clean $file) -}} {{- end -}} {{- $extension := strings.TrimLeft "." (path.Ext $file) -}} {{- $captureStart := "" -}} {{- $captureEnd := "" -}} {{- $supportedExtensions := slice "js" "scss" "toml" -}} {{- if in $supportedExtensions $extension -}} {{- if eq $extension "toml" -}} {{- $captureStart = printf "# toml-docs-start %s" $args.name -}} {{- $captureEnd = printf "# toml-docs-end %s" $args.name -}} {{- else -}} {{- $captureStart = printf "// %s-docs-start %s" $extension $args.name -}} {{- $captureEnd = printf "// %s-docs-end %s" $extension $args.name -}} {{- end -}} {{- else -}} {{- errorf "File format not supported (line %s): %s" .Position $file -}} {{- end -}} {{/* Main code */}} {{- if not $error -}} {{- $statResult := try (os.Stat $file) -}} {{- if $statResult.Err -}} {{- warnf "shortcodes/docs.md - Cannot find file: %q. Skipping." $file -}} {{- $error = true -}} {{- end -}} {{- end -}} {{- if not $error -}} {{- $regex := printf `%s((?:.|\n)*)%s` $captureStart $captureEnd -}} {{- $match := findRE $regex (readFile $file) -}} {{- $match = index $match 0 -}} {{- if not $match -}} {{- errorf "%s: %q: Got no matches for name=%q in file=%q!" .Position .Name $args.name $file -}} {{- end -}} {{- $match = replace $match $captureStart "" -}} {{- $match = replace $match $captureEnd "" -}} ```{{ $extension }} {{ trim $match "\r\n" }} ``` {{- end -}} ================================================ FILE: layouts/_shortcodes/example-bookshop.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. This source code adapts the original embedded shortcode as maintained by the The Bootstrap Authors. It introduces the following modifications: - Added validation of shortcode arguments - Modified the layout - Added support to render bookshop components The original source code is available on: Source: https://github.com/twbs/bootstrap/blob/main/site/layouts/shortcodes/example.html Copyright (c) 2011-2023 The Bootstrap Authors. Licensed under The MIT License (MIT). */}} {{ $error := false -}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "example" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/example-bookshop.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err }} {{- end -}} {{/* Initialize local arguments */}} {{- $lang := $args.lang -}} {{- $showPreview := $args.showPreview }} {{- $showMarkup := $args.showMarkup }} {{- if eq $lang "hugo" }}{{ $lang = "markdown" }}{{ end -}} {{- $content := .InnerDeindent -}} {{- $padding := partial "utilities/GetPadding.html" -}} {{- $sectionClass := printf "p-1 px-md-%d py-md-%d" $padding.x $padding.y -}} {{- $bgClass := printf "m-n1 mx-md-n%d my-md-n%d" $padding.x $padding.y -}} {{- $data := "" -}} {{- $partial := "" -}} {{- $type := "shortcode" }} {{- if eq $lang "hugo" }}{{ $lang = "markdown" }}{{ end -}} {{- if eq $lang "bookshop" }} {{ $type = "bookshop" }} {{ $frontmatter := slice "yml" "yaml" "toml" "json" }} {{ $inputRE := findRESubmatch `\x60\x60\x60(?:yml|yaml|json|toml)(\r\n|\r|\n)([\s\S]*?)\x60\x60\x60` $content 1 }} {{ if and $inputRE (eq (len (index $inputRE 0)) 3) }} {{ $lang = (trim (index (split $content "\n") 2) "\x60") | default "yml" }} {{ $content = index (index $inputRE 0) 2 }} {{ $data = index (unmarshal $content) 0 }} {{ $data = merge $data (dict "section_class" $sectionClass "bg_class" $bgClass) }} {{ $component_name := (index $data "_bookshop_name") }} {{ if not $component_name }} {{ errorf "Expected '_bookshop_name': %s" .Position -}} {{ $error = true }} {{ else }} {{ $partial = partial "_bookshop/helpers/component.html" (slice $component_name $data) }} {{ end }} {{ else }} {{ errorf "Expected frontmatter codeblock as input: %s" .Position -}} {{ $error = true }} {{ end }} {{ end -}} {{/* Main code */}} {{ if not $error }}
    {{- if eq $showPreview true -}}
    {{ if eq $type "bookshop" }} {{ $partial | safeHTML }} {{ else }} {{- $content | .Page.RenderString | safeHTML -}} {{ end }}
    {{- end -}} {{- if eq $showMarkup true -}}
    {{ $lang }}
    {{- highlight (trim $content "\r\n") $lang "" | safeHTML -}}
    {{- end -}}
    {{ end }} ================================================ FILE: layouts/_shortcodes/example-bookshop.md ================================================ {{ .Inner -}} ================================================ FILE: layouts/_shortcodes/example.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. This source code adapts the original embedded shortcode as maintained by the The Bootstrap Authors. It introduces the following modifications: - Added validation of shortcode arguments - Modified the layout The original source code is available on: Source: https://github.com/twbs/bootstrap/blob/main/site/layouts/shortcodes/example.html Copyright (c) 2011-2023 The Bootstrap Authors. Licensed under The MIT License (MIT). */}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "example" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/example.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{- end -}} {{/* Initialize arguments */}} {{- $lang := $args.lang -}} {{- $showPreview := $args.showPreview }} {{- $showMarkup := $args.showMarkup }} {{- if eq $lang "hugo" }}{{ $lang = "markdown" }}{{ end -}} {{- $content := .InnerDeindent -}} {{/* Main code */}} {{ if not $args.err }}
    {{- if $showPreview -}}
    {{- if eq $lang "html" -}} {{- $content | safeHTML -}} {{- else -}} {{- $content | .Page.RenderString | safeHTML -}} {{- end -}}
    {{- end -}} {{- if $showMarkup -}}
    {{- $lang -}}
    {{- highlight (trim $content "\r\n") $lang "" | safeHTML -}}
    {{- end -}}
    {{ end }} ================================================ FILE: layouts/_shortcodes/example.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "example" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} {{- $lang := $args.lang -}} {{- if eq $lang "hugo" -}}{{- $lang = "markdown" -}}{{- end -}} {{- printf "```%s\n%s\n```" $lang (trim .InnerDeindent "\r\n") -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/file.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. This source code adapts the original embedded shortcode as maintained by the The Bootstrap Authors. It introduces the following modifications: - Added validation of shortcode arguments - Modified the layout The original source code is available on: Source: https://github.com/twbs/bootstrap/blob/main/site/layouts/shortcodes/scss-docs.html Copyright (c) 2011-2023 The Bootstrap Authors. Licensed under The MIT License (MIT). */}} {{ $error := false -}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "file" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/file.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err }} {{- end -}} {{/* Initialize arguments */}} {{- $basePath := .Site.Params.docs.basePath -}} {{- $file := or $args.file $args.path -}} {{ if $file }} {{- if hasPrefix $file "./" -}} {{- $file = path.Clean $file -}} {{- else -}} {{- $file = path.Join $basePath (path.Clean $file) -}} {{- end -}} {{ if not (fileExists $file) }} {{ warnf "Cannot find file: '%q'. See %s" $file $.Position }} {{ $error = true }} {{ end }} {{ else }} {{ errorf "Expected file or path argument. See %s" $.Position }} {{ $error = true }} {{ end }} {{- $extension := strings.TrimLeft "." (path.Ext $file) }} {{- $lang := $args.lang | default $extension -}} {{- $id := $args.id | default (printf "file-collapse-%d" .Ordinal) -}} {{/* Main code */}} {{- if not $error -}} {{- /* Force-check if the file exists */ -}} {{- $tmp := os.Stat $file -}} {{- $content := readFile $file -}}
    {{- highlight (trim $content "\r\n") $lang (or $args.highlightOptions $args.options) -}}
    {{- end -}} ================================================ FILE: layouts/_shortcodes/file.md ================================================ {{- $error := false -}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "file" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if $args.err -}}{{- $error = true -}}{{- end -}} {{- if not $error -}} {{- $basePath := .Site.Params.docs.basePath -}} {{- $file := or $args.file $args.path -}} {{- if $file -}} {{- if hasPrefix $file "./" -}}{{- $file = path.Clean $file -}}{{- else -}}{{- $file = path.Join $basePath (path.Clean $file) -}}{{- end -}} {{- if fileExists $file -}} {{- $extension := strings.TrimLeft "." (path.Ext $file) -}} {{- $lang := $args.lang | default $extension -}} {{- $content := readFile $file -}} {{- printf "```%s\n%s\n```" $lang (trim $content "\r\n") -}} {{- end -}} {{- end -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/image.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $error := false }} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "image" "child" "nav-item" "args" .Params "group" "shortcode" "named" .IsNamedParams) }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/image.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err }} {{- end -}} {{/* Initialize arguments */}} {{- $src := or $args.src $args.url -}} {{ if not $src }} {{ errorf "Missing value for param 'src': %s" .Position -}} {{- $error = true -}} {{ end }} {{/* Main code */}} {{- if not $error -}} {{- partial "assets/image.html" (dict "src" $src "ratio" $args.ratio "wrapper" $args.wrapper "class" $args.class "title" $args.title "caption" $args.caption "figclass" $args.figclass "mode" $args.mode "portrait" $args.portrait "plain" $args.plain "anchor" $args.anchor "loading" $args.loading "page" .Page "_default" $args.default ) -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/image.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "image" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} {{- $src := or $args.src $args.url -}} {{- $alt := or $args.title $args.caption "image" -}} ![{{ $alt }}]({{ $src }}) {{- end -}} ================================================ FILE: layouts/_shortcodes/img.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "carousel-item" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/carousel-item.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{- end -}} {{/* Initialize local arguments */}} {{ if not .Parent }} {{ errorf "The img shortcode should be contained within a carousel shortcode: %s" .Position }} {{ else if not $args.err }} {{- $ratio := partial "utilities/GetArgParent" (dict "page" . "arg" "ratio") -}} {{- $portrait := partial "utilities/GetArgParent" (dict "page" . "arg" "portrait") | default false -}} {{/* Main code */}} {{- $output := partial "assets/carousel-item.html" (dict "page" .Page "active" (or $args.active (eq .Ordinal 0)) "src" $args.src "caption" $args.caption "ratio" $ratio "portrait" $portrait "loading" $args.loading ) }} {{ $current := .Parent.Scratch.Get "inner" }} {{ if $current }} {{ .Parent.Scratch.Set "inner" (print $current $output) }} {{ else }} {{ .Parent.Scratch.Set "inner" $output }} {{ end }} {{ end -}} ================================================ FILE: layouts/_shortcodes/img.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "carousel-item" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} ![{{ $args.caption | default "image" }}]({{ $args.src }}) {{- end -}} ================================================ FILE: layouts/_shortcodes/ins.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $error := false -}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "ins" "args" .Params) }} {{ if $args.err }} {{ partial "utilities/LogErr.html" (dict "partial" "shortcodes/ins.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" $args.errmsg "file" page.File )}} {{ end }} {{ $text := .Inner | default "" }} {{/* Main code */}} {{- if not $error -}} {{ $text | strings.TrimSpace | .Page.RenderString }} {{- end -}} ================================================ FILE: layouts/_shortcodes/ins.md ================================================ {{ trim .Inner " \r\n" | plainify -}} ================================================ FILE: layouts/_shortcodes/kbd.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{- $error := false -}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "kbd" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/kbd.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position ) -}} {{- $error = $args.err -}} {{- end -}} {{/* Initialize local arguments */}} {{- $text := trim (or $args.text $args.title) " \n\r" }} {{- if not $text -}} {{- partial "utilities/LogErr.html" (dict "partial" "shortcodes/kbd.html" "msg" "Invalid arguments" "details" (slice "argument 'text': expected value") "file" page.File "position" .Position ) -}} {{- $error = true -}} {{- end -}} {{/* Main code */}} {{- if not $error }} {{- $text -}} {{ end -}} ================================================ FILE: layouts/_shortcodes/kbd.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "kbd" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} `{{ trim .Inner " \r\n" }}` {{- end -}} ================================================ FILE: layouts/_shortcodes/link.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "link" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/link.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position ) -}} {{- end -}} {{/* Initialize arguments */}} {{- $destination := or $args.href $args.name $args.url -}} {{- $text := chomp .Inner -}} {{- if and site.Params.main.titleCase (not .Page.Params.exact) }}{{ $text = title $text }}{{ end -}} {{- $text = $text | .Page.RenderString | safeHTML -}} {{/* Main code */}} {{- if not $args.err -}} {{ partial "assets/link.html" (dict "href" $destination "text" $text "cue" $args.cue "tab" $args.tab "case" $args.case "exact" $args.exact "title" $args.title "external" $args.external "force" $args.force "class" $args.class "page" .Page "position" .Position "_default" $args.default ) }} {{- end -}} ================================================ FILE: layouts/_shortcodes/link.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "link" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} {{- $destination := or $args.href $args.name $args.url -}} {{- $text := chomp .Inner | plainify -}} [{{ $text }}]({{ $destination }}) {{- end -}} ================================================ FILE: layouts/_shortcodes/mark.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "mark" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/mark.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{- end -}} {{/* Initialize local arguments */}} {{- $class := $args.class -}} {{- if $args.color }}{{ $class = printf "%s text-bg-%s" $class $args.color }}{{ end -}} {{/* Main code */}} {{- if not $args.error -}} {{ trim .Inner " \r\n" | .Page.RenderString -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/mark.md ================================================ {{ trim .Inner " \r\n" | plainify -}} ================================================ FILE: layouts/_shortcodes/nav-item.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "nav-item" "args" .Params "group" "shortcode" "named" .IsNamedParams) -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/nav-item.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position ) -}} {{- end -}} {{/* Initialize arguments */}} {{- if not .Parent -}} {{- errorf "The nav-item shortcode should be contained within a nav shortcode: %s" .Position -}} {{- else if not $args.err -}} {{- $id := .Ordinal -}} {{- $parent := printf "nav-%d" .Parent.Ordinal -}} {{- with (.Parent.Get "id") }}{{ $parent = . }}{{ end -}} {{- $fade := $args.fade -}} {{- $parentFade := false }} {{- if isset .Parent.Params "fade" }}{{ $parentFade = partial "utilities/CastBool.html" (.Parent.Get "fade") }}{{ end -}} {{- $fade = or $fade $parentFade -}} {{- $title := or $args.title $args.header -}} {{- $itemID := printf "%s-btn-%d" $parent $id }} {{- $disabledID := cond $args.disabled $itemID "" }} {{- $body := trim .Inner " \r\n" -}} {{- $current := "" -}} {{/* Main code */}} {{- $output := partial "assets/nav-item.html" (dict "page" .Page "id" $id "parent-id" $parent "fade" $fade "title" $title "class" $args.class "body" $body "show" $args.show "disabled" $args.disabled "_default" $args.default ) -}} {{- $current := .Parent.Scratch.Get "inner" -}} {{- $titles := .Parent.Scratch.Get "inner-title" -}} {{- $disabled := .Parent.Scratch.Get "inner-disabled" -}} {{- $icons := .Parent.Scratch.Get "inner-icon" -}} {{- $itemAttrs := .Parent.Scratch.Get "inner-attrs" -}} {{- if $args.show }}{{ .Parent.Scratch.Set "inner-show" $itemID }}{{ end -}} {{- if $current -}} {{- .Parent.Scratch.Set "inner" (print $current $output) -}} {{- .Parent.Scratch.Set "inner-title" ($titles | append $title) -}} {{- .Parent.Scratch.Set "inner-disabled" ($disabled | append $disabledID) -}} {{- .Parent.Scratch.Set "inner-icon" ($icons | append $args.icon) -}} {{- .Parent.Scratch.Set "inner-attrs" ($itemAttrs | append $args.attributes) -}} {{- else -}} {{- .Parent.Scratch.Set "inner" $output -}} {{- .Parent.Scratch.Set "inner-title" (slice $title) -}} {{- .Parent.Scratch.Set "inner-disabled" (slice $disabledID) -}} {{- .Parent.Scratch.Set "inner-icon" (slice $args.icon) -}} {{- .Parent.Scratch.Set "inner-attrs" (slice $args.attributes) -}} {{- end }} {{- $alternative := partial "assets/nav-item.html" (dict "page" .Page "id" $id "parent-id" $parent "fade" $fade "title" $title "class" $args.class "body" $body "show" $args.show "disabled" $args.disabled "navitem-type" "accordion" "_default" $args.default ) -}} {{- $current := .Parent.Scratch.Get "alternative" -}} {{- if $current -}} {{- .Parent.Scratch.Set "alternative" (print $current $alternative) -}} {{- else -}} {{- .Parent.Scratch.Set "alternative" $alternative -}} {{ end }} {{ end }} ================================================ FILE: layouts/_shortcodes/nav-item.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "nav-item" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} {{- $title := or $args.title $args.header -}} {{ with $title }}### {{ . }} {{ end -}} {{ trim .Inner " \r\n" }} {{- end -}} ================================================ FILE: layouts/_shortcodes/nav.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "nav" "args" .Params "group" "shortcode" "named" .IsNamedParams) -}} {{- if or $args.err $args.warnmsg -}} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/nav.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position ) -}} {{- end -}} {{- $inner := .Scratch.Get "inner" -}} {{- $innerTitles := .Scratch.Get "inner-title" -}} {{- $innerDisabled := .Scratch.Get "inner-disabled" -}} {{- $innerShow := .Scratch.Get "inner-show" -}} {{- $innerIcons := .Scratch.Get "inner-icon" -}} {{- $innerAttrs := .Scratch.Get "inner-attrs" -}} {{- $input := trim .Inner " \r\n" -}} {{- if $input -}} {{- $input = replace $input "\n" "\n " -}} {{- warnf "Unexpected inner content: %s\r\n %s" .Position $input -}} {{- end -}} {{/* Main code */}} {{- if not $args.err -}} {{- partial "assets/nav.html" (dict "id" (or $args.id (printf "nav-%d" .Ordinal)) "page" .Page "list" $args.list "nav-items" $inner "nav-titles" $innerTitles "nav-disabled" $innerDisabled "nav-show" $innerShow "nav-icons" $innerIcons "nav-item-attrs" $innerAttrs "tab-type" (or $args.tabType $args.type) "align" $args.align "controls-placement" $args.controlsPlacement "attributes" $args.attributes "vertical" $args.vertical "word-wrap" $args.wordWrap "responsive" $args.responsive "class" $args.class "pane" $args.pane "width" $args.width "_default" $args.default ) -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/nav.md ================================================ {{ .Inner -}} ================================================ FILE: layouts/_shortcodes/navbar.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $error := false }} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "navbar" "args" .Params "group" "shortcode" "named" .IsNamedParams) }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/navbar.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error := $args.err }} {{- end -}} {{/* Initialize arguments */}} {{- $id := $args.id | default (printf "navbar-collapse-%d" (add .Ordinal 1)) -}} {{ $page := .Page }} {{ if $args.path }}{{ $page = .Site.GetPage $args.path }}{{ end }} {{ if and $args.path (not $page) }} {{ errorf "Cannot find page '%s': %s" $args.path .Position -}} {{ $error = true -}} {{ end }} {{/* Main code */}} {{ if not $error -}} {{- partial "assets/navbar.html" (dict "id" $id "page" $page "breakpoint" (or $args.breakpoint $args.size) "style" $args.style "color" $args.color "search" $args.search "mode" $args.mode "menu" (or $args.menu $args.menus) "logo" $args.logo "logo-align" $args.logoAlign "logo-mode" $args.logoMode "title" $args.title "transparent" $args.transparent "class" $args.class "_default" $args.default ) -}} {{ end -}} ================================================ FILE: layouts/_shortcodes/navbar.md ================================================ {{- /* Navbar is decorative — no meaningful output for LLM */ -}} ================================================ FILE: layouts/_shortcodes/persona.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{- $error := false }} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "persona" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/persona.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err }} {{- end -}} {{/* Initialize local arguments */}} {{ if $args.path }} {{- if not .Site.GetPage $args.path -}} {{- errorf "Invalid or missing value for param 'path': %s" .Position -}} {{- $error = true -}} {{- end -}} {{ end }} {{- $content := trim .Inner " \r\n" | .Page.RenderString -}} {{/* Main code */}} {{- if not $error -}} {{- partial "assets/persona.html" (dict "path" $args.path "class" $args.class "color" $args.color "title" $args.title "href" $args.href "content" $content "thumbnail" $args.thumbnail "_default" $args.default ) -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/persona.md ================================================ {{ .Inner -}} ================================================ FILE: layouts/_shortcodes/release.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "release" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/release.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{- end -}} {{/* Initialize local arguments */}} {{- $title := $args.version -}} {{- $state := or $args.releaseState $args.state -}} {{- $color := cond (eq $state "deprecated") "secondary" "primary" -}} {{- $linkType := or $args.linkType $args.type -}} {{- $release := partial "utilities/GetThemeIcon.html" (dict "id" "release" "default" dict) -}} {{- $icon := "" -}} {{- $tooltip := "" -}} {{- if eq $state "deprecated" -}} {{- if $args.short -}} {{- $icon = ($release.deprecated | default "fas trash-can") -}} {{- $tooltip = T "deprecatedFeature" $args.version -}} {{ else }} {{- $title = T "deprecatedFeature" $args.version -}} {{- end -}} {{- else -}} {{- if $args.short -}} {{- $icon = ($release.feature | default "fas rocket") -}} {{- $tooltip = T "addedFeature" $args.version -}} {{ else }} {{- $title = T "addedFeature" $args.version -}} {{- end -}} {{- end -}} {{- if not $args.short -}} {{- if eq $state "deprecated" -}} {{- $title = T "deprecatedFeature" $args.version -}} {{- else -}} {{- $title = T "addedFeature" $args.version -}} {{- end -}} {{- end -}} {{/* Main code */}} {{- if not $args.error -}} {{ $href := partial "utilities/URLJoin.html" (dict "base" site.Params.docs.release "path" $args.version) }} {{ if eq $linkType "link" }} {{ partial "assets/link.html" (dict "href" $href "text" $title "page" .Page) }} {{ else }} {{- if not $args.inline }}
    {{ end -}} {{- partial "assets/button.html" (dict "title" $title "href" $href "color" $color "outline" "true" "button-size" (or $args.buttonSize $args.size) "icon" $icon "tooltip" $tooltip "order" "first" "class" (trim (printf "rounded-2 fw-semibold %s" $args.class) " ") "spacing" $args.inline ) -}} {{- if not $args.inline }}
    {{ end -}} {{ end }} {{- end -}} ================================================ FILE: layouts/_shortcodes/release.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "release" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} {{- $state := or $args.releaseState $args.state -}} {{- if eq $state "deprecated" -}} {{- T "deprecatedFeature" $args.version -}} {{- else -}} {{- T "addedFeature" $args.version -}} {{- end -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/spinner.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "spinner" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/spinner.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{- end -}} {{/* Main code */}} {{- if not $args.error -}} {{- with $args.class }}
    {{ end -}}
    {{ trim .Inner " \r\n" | plainify -}}
    {{- if $args.class }}
    {{ end -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/spinner.md ================================================ {{- /* Spinner is decorative — no meaningful output for LLM */ -}} ================================================ FILE: layouts/_shortcodes/sub.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "sub" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/sub.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{- end -}} {{- if not $args.error -}} {{ $args.text | .Page.RenderString -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/sub.md ================================================ {{ trim .Inner " \r\n" | plainify -}} ================================================ FILE: layouts/_shortcodes/sup.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{- $args := partial "utilities/InitArgs.html" (dict "structure" "sup" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if or $args.err $args.warnmsg -}} {{- partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/sup.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{- end -}} {{- if not $args.error -}} {{ $args.text | .Page.RenderString -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/sup.md ================================================ {{ trim .Inner " \r\n" | plainify -}} ================================================ FILE: layouts/_shortcodes/table.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "table" "args" .Params "group" "shortcode" "named" .IsNamedParams) }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/table.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{- end -}} {{/* Main code */}} {{ if not $args.err }} {{ partial "assets/table.html" (dict "page" .Page "input" .Inner "breakpoint" $args.breakpoint "class" $args.class "sortable" $args.sortable "paginate" $args.paginate "pagination" (or $args.pagination $args.pagingOptionPerPage) "pagination-select" (or $args.paginationSelect $args.pagingOptionPageSelect) "searchable" $args.searchable "wrap" $args.wrap "wrapper" $args.wrapper "_default" $args.default ) }} {{ end }} ================================================ FILE: layouts/_shortcodes/table.md ================================================ {{ .Inner -}} ================================================ FILE: layouts/_shortcodes/testimonial.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $error := false }} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "testimonial" "args" .Params "group" "shortcode" "named" .IsNamedParams) }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/testimonial.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err }} {{- end -}} {{/* Initialize arguments */}} {{/* Main code */}} {{- if not $error -}}
    {{ $class := "" }} {{ with $args.color }} {{ $class = printf "%s text-bg-%s" (partial "utilities/GetBackgroundStyle" (dict "background" .)) . }} {{ end }} {{- partial "assets/testimonial.html" (dict "page" .Page "content" .Inner "logo" $args.logo "icon" $args.icon "icon-style" $args.iconStyle "align" $args.align "contact" $args.contact "role" $args.role "image" $args.image "url" $args.url "padding" $args.padding "orientation" $args.orientation "show-controls" false "link" $args.link "color" $args.color "class" $class ) -}}
    {{- end -}} ================================================ FILE: layouts/_shortcodes/testimonial.md ================================================ "{{ trim .Inner "\r\n " }}" {{ with .Get "contact" }}— {{ . }}{{ with $.Get "role" }}, {{ . }}{{ end }}{{ with $.Get "url" }} ({{ . }}){{ end }} {{ end -}} ================================================ FILE: layouts/_shortcodes/timeline.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. Inspired by the timeline snippet from Siddharth Panchal at https://bootsnipp.com/snippets/Q0ppE */}} {{ $error := false }} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "timeline" "args" .Params "named" .IsNamedParams "group" "shortcode") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/timeline.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err }} {{ end }} {{/* Initialize local arguments */}} {{- $page := .Page -}} {{- $data := partial "utilities/GetI18nData.html" (dict "page" $page "data" $args.data) }} {{ if and (not $data) (not $args.section) -}} {{ errorf "Invalid timeline data '%s': %s" $args.data .Position -}} {{ $error = true }} {{ end -}} {{/* Main code */}} {{ if not $error }} {{ partial "assets/timeline.html" (dict "page" $page "data" $args.data "section" $args.section "limit" $args.limit "layout" $args.layout "background" $args.background "class" $args.class "justify" $args.justify "_default" $args.default ) }} {{ end }} ================================================ FILE: layouts/_shortcodes/timeline.md ================================================ {{ .Inner -}} ================================================ FILE: layouts/_shortcodes/toast.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $error := false }} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "toast" "args" .Params "named" .IsNamedParams "group" "shortcode") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/toast.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err }} {{ end }} {{/* Initialize local arguments */}} {{- $id := $args.id | default (printf "toast-message-%d" .Ordinal) -}} {{ $message := trim .Inner " \r\n" | .Page.RenderString -}} {{ if not $message -}} {{ errorf "Missing inner element text: %s" .Position -}} {{ $error = true }} {{ end }} {{/* Main code */}} {{ if not $error -}} {{ partial "assets/toast.html" (dict "id" $id "title" (or $args.title $args.header) "message" $message "class" $args.class "_default" $args.default ) }} {{ end -}} ================================================ FILE: layouts/_shortcodes/toast.md ================================================ {{- /* Toast is decorative — no meaningful output for LLM */ -}} ================================================ FILE: layouts/_shortcodes/tooltip.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{ $error := false }} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "tooltip" "args" .Params "named" .IsNamedParams "group" "shortcode") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/tooltip.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ $error = $args.err }} {{ end }} {{/* Initialize local arguments */}} {{ $title := trim .Inner " \r\n" | plainify -}} {{ if not $title -}} {{ errorf "Missing inner element text: %s" .Position -}} {{ $error = true }} {{ end -}} {{/* Main code */}} {{ if not $error }}
    {{- partial "assets/button.html" (dict "link-type" "link" "title" $title "color" $args.color "tooltip" $args.title "href" $args.href "placement" $args.placement "class" $args.class "spacing" $args.spacing) -}}
    {{ end }} ================================================ FILE: layouts/_shortcodes/tooltip.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "tooltip" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} {{ trim .Inner " \r\n" | plainify -}} {{- end -}} ================================================ FILE: layouts/_shortcodes/video.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "video" "args" .Params "named" .IsNamedParams "group" "shortcode") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/video.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ end }} {{/* Main code */}} {{ if not $args.err }} {{ partial "assets/video.html" (dict "page" .Page "position" .Position "account" $args.account "provider" (or $args.host $args.provider) "media-id" (or $args.mediaId $args.id) "class" $args.class "title" $args.title "autoplay" $args.autoplay "autotitle" $args.autotitle "_default" $args.default ) }} {{ end -}} ================================================ FILE: layouts/_shortcodes/video.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "video" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} {{- $title := $args.title | default "Video" -}} {{- $provider := or $args.host $args.provider -}} {{- $id := or $args.mediaId $args.id -}} [Video: {{ $title }}]{{ with $provider }} ({{ . }}{{ with $id }}: {{ . }}{{ end }}){{ end }} {{- end -}} ================================================ FILE: layouts/_shortcodes/vimeo.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "video" "args" .Params "named" .IsNamedParams "group" "shortcode") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/vimeo.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ end }} {{/* Main code */}} {{ if not $args.err }} {{ partial "assets/video.html" (dict "page" .Page "position" .Position "provider" "vimeo" "media-id" (or $args.mediaId $args.id) "class" $args.class "title" (or $args.title "Vimeo Video") "autoplay" $args.autoplay "autotitle" $args.autotitle "_default" $args.default ) }} {{ end -}} ================================================ FILE: layouts/_shortcodes/vimeo.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "video" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} [{{ or $args.title "Vimeo Video" }}](https://vimeo.com/{{ or $args.mediaId $args.id }}) {{- end -}} ================================================ FILE: layouts/_shortcodes/youtube.html ================================================ {{/* Copyright © 2022 - 2026 The Hinode Team / Mark Dumay. All rights reserved. Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file. Visit gethinode.com/license for more details. */}} {{/* Initialize arguments */}} {{ $args := partial "utilities/InitArgs.html" (dict "structure" "video" "args" .Params "named" .IsNamedParams "group" "shortcode") }} {{ if or $args.err $args.warnmsg }} {{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict "partial" "shortcodes/youtube.html" "warnid" "warn-invalid-arguments" "msg" "Invalid arguments" "details" ($args.errmsg | append $args.warnmsg) "file" page.File "position" .Position )}} {{ end }} {{/* Main code */}} {{ if not $args.err }} {{ partial "assets/video.html" (dict "page" .Page "position" .Position "provider" "youtube" "media-id" (or $args.mediaId $args.id) "class" $args.class "title" (or $args.title "YouTube Video") "autoplay" $args.autoplay "autotitle" $args.autotitle "_default" $args.default ) }} {{ end -}} ================================================ FILE: layouts/_shortcodes/youtube.md ================================================ {{- $args := partial "utilities/InitArgs.html" (dict "structure" "video" "args" .Params "named" .IsNamedParams "group" "shortcode") -}} {{- if not $args.err -}} [{{ or $args.title "YouTube Video" }}](https://www.youtube.com/watch?v={{ or $args.mediaId $args.id }}) {{- end -}} ================================================ FILE: layouts/alias.html ================================================ {{ $lang := site.Language.Lang }} {{ .Permalink }} {{ if and page site.Params.main.enableLanguageSelectionStorage }} {{- partial "footer/scripts.html" (dict "page" page "type" "critical") -}} {{- partial "footer/scripts.html" (dict "page" page "type" "functional") -}} {{ else }} {{ end }} ================================================ FILE: layouts/baseof.html ================================================ {{- /* Set version-aware sidebar menu */ -}} {{- $version := partial "utilities/GetVersion.html" (dict "page" . "base" true) -}} {{- $.Scratch.Set "version" $version -}} {{ with partial "utilities/GetMenu" (dict "page" . "version" $version) }}{{ $.Scratch.Set "sidebar" . }}{{ end }} {{- /* Validate if current version is latest */ -}} {{- if and site.Params.docs.checkVersion $version -}} {{- if ne $version "latest" -}} {{- if partial "utilities/IsOlder" (dict "current" $version) -}} {{- $.Scratch.Set "pageAlertMsg" (T "newerVersionAlert" site.Title) -}} {{- $.Scratch.Set "pageAlertURL" (or site.Params.docs.latestURL site.baseURL) -}} {{- end -}} {{- end -}} {{- end -}} {{- /* Initialize module configuration */ -}} {{- $modules := partialCached "utilities/InitModules.html" . -}} {{- $.Scratch.Set "modules" $modules -}} {{- $fullCover := or (or (and .IsHome .Site.Params.home.fullCover) .Page.Params.fullCover) .Site.Params.main.footerBelowFold }} {{- $.Scratch.Set "fullCover" $fullCover -}} {{- /* Define main breakpoint */ -}} {{- $.Scratch.Set "breakpoint" (partialCached "utilities/GetBreakpoint.html" .) }} {{- /* Define page metadata */ -}} {{- $.Scratch.Set "metadata" (partial "utilities/GetMetadata.html" .) }} {{- /* Define page sharing */ -}} {{- $.Scratch.Set "sharing" (partial "utilities/GetSharing.html" .) }} {{- /* Define TOC inclusion */ -}} {{- $.Scratch.Set "includeToc" (partial "utilities/GetIncludeToc.html" .) }} {{- /* Prepare content blocks and establish overlay mode */ -}} {{ $overlayMode := $.Scratch.Get "overlayMode" }} {{- /* Define base URL */ -}} {{ $lang := site.Language.Lang }} {{ $.Scratch.Set "baseURL" (strings.TrimSuffix (printf "%s/" $lang) site.Home.RelPermalink) }} {{- partial "footer/scripts.html" (dict "page" . "type" "critical") -}} {{- partial "footer/scripts.html" (dict "page" . "type" "functional") -}} {{ block "head" . }}{{ end -}} {{- $belowFold := site.Params.main.footerBelowFold -}} {{- $navFixed := site.Params.navigation.fixed -}} {{- $bodyClasses := slice -}} {{- if $belowFold }}{{ $bodyClasses = $bodyClasses | append "footer-below-fold" }}{{ end -}} {{- if $navFixed }}{{ $bodyClasses = $bodyClasses | append "navbar-fixed" }}{{ end -}} {{- partial "assets/navbar.html" (dict "page" . "fixed" site.Params.navigation.fixed "overlay" site.Params.navigation.overlay "overlayMode" site.Params.navigation.overlayMode "transparent" site.Params.navigation.transparent "color" site.Params.navigation.color "style" (default "light" site.Params.navigation.style) "breakpoint" (default "md" site.Params.navigation.size)) -}}
    {{ block "main" . }}{{ end -}}
    {{ if and (eq .Kind "page") (eq (len (or .Params.content_blocks slice)) 0) (eq (len .RawContent) 0)}} {{- partial "utilities/LogWarn.html" (dict "partial" "layouts/baseof.html" "warnid" "warn-empty-page" "msg" "No content" "details" "Page has no content or blocks defined" "file" .File ) -}} {{ end }} {{- partial "footer/social.html" . -}} {{- partial "footer/footer.html" . -}} {{- partial "footer/toast-container.html" . -}} {{- partial "assets/symbols.html" . -}} {{- partial "assets/modals.html" . -}} {{- partialCached "footer/scripts.html" (dict "page" .) -}} {{- partial "footer/scripts.html" (dict "page" . "type" "optional") -}} ================================================ FILE: layouts/baseof.xml ================================================ {{ printf "" | safeHTML }} {{ block "main" . }}{{ end }} ================================================ FILE: layouts/body.html ================================================ {{- partial "page/thumbnail.html" (dict "page" . "wrapper" "mb-5") -}} {{ partial "utilities/ProcessContent" (dict "page" .Page "raw" .RawContent) }} ================================================ FILE: layouts/docs/all.html ================================================ {{/* Derived from layouts/single.html template, but applied to all docs pages (list and single) */}} {{/* Inserts auto-generated sidebar with section navigation */}} {{/* Renders blocks inside main body */}} {{ define "main" -}} {{- $breakpoint := $.Scratch.Get "breakpoint" -}} {{- $padding := partial "utilities/GetPadding.html" -}} {{/* Auto-generated sidebar for docs */}} {{- $menu := .Scratch.Get "sidebar" -}} {{- if not (reflect.IsSlice $menu) }}{{ $menu = "" }}{{ end }} {{- $version := .Scratch.Get "version" -}} {{- $sidebar := partial "assets/sidebar.html" (dict "page" . "menu" $menu "version" $version "auto-generate" true) -}} {{/* Render the offcanvas sidebar */}} {{- partial "page/sidebar-offcanvas.html" (dict "section" $.Section "raw" $sidebar) -}} {{/* Render the page content using responsive columns */}}
    {{/* Render the defined content blocks, using the default articles element as fallback for list pages */}} {{ if .Params.content_blocks }} {{- $.Scratch.Set "blocks_embed" true -}} {{- partial "page/blocks.html" . -}} {{ else if eq .Kind "section" }} {{ $.Scratch.Set "articlesParams" (dict "sort" "weight" "reverse" false "class" "card-emphasize border h-100" "header-style" "none" "icon-style" "text-primary fa-xl" "padding" $padding.x ) }} {{ partial "page/articles.html" . }} {{ else }} {{ .Render "header" }} {{ end }} {{ .Render "body" }} {{ .Render "footer" }}
    {{ .Render "toc" }}
    {{ end -}} ================================================ FILE: layouts/docs/body.html ================================================ {{ partial "utilities/ProcessContent" (dict "page" .Page "raw" .RawContent) }} ================================================ FILE: layouts/docs/footer.html ================================================
    {{ partial "utilities/git.html" . }}
    ================================================ FILE: layouts/docs/header.html ================================================ {{/* Initialize global variables */}} {{- $size := .Site.Params.style.title.size | default 4 -}} {{- $headingStyle := .Site.Params.style.title.headingStyle | default "display" -}} {{- $contentStyle := .Site.Params.style.title.contentStyle | default "lead text-muted" -}} {{- $padding := partial "utilities/GetPadding.html" -}} {{- $sharing := .Scratch.Get "sharing" -}} {{/* Initialize local variables */}} {{- $breakpoint := .Scratch.Get "breakpoint" -}} {{ $title := .Title }} {{ if and .Site.Params.main.titleCase (not .Params.exact) }}{{ $title = title $title }}{{ end }} {{/* Render breadcrumb */}} {{ if .Site.Params.navigation.breadcrumb }}{{ partial "assets/breadcrumb.html" (dict "page" .) }}{{ end -}} {{/* Display title and metadata */}} {{ with $title }}

    {{ . }}

    {{ end }} {{/* Ignore metadata */}} {{/* Ignore tags */}} {{/* Display social sharing buttons */}} {{- if $sharing }}
    {{ partial "page/sharing.html" . }}
    {{ end -}} {{/* Display description */}} {{ with .Description }}
    {{ . | $.RenderString | safeHTML }}
    {{ end }} {{/* Display TOC dropdown on smaller screens */}} {{- if and .Site.Params.navigation.toc .Params.includeToc | default true -}}
    {{ partial "assets/toc-dropdown.html" (dict "page" .) }}
    {{- end -}} ================================================ FILE: layouts/footer.html ================================================ {{/* Render previous / next navigation */}} {{- partial "page/navigation.html" . -}} ================================================ FILE: layouts/form/single.html ================================================ {{ define "main" }} {{- $padding := partial "utilities/GetPadding.html" -}} {{- $formIcon := partial "utilities/GetThemeIcon.html" (dict "id" "formSubmittedIcon" "default" "fa envelope") -}}
    {{ partial "assets/icon.html" (dict "icon" $formIcon "class" "fa-10x") }}

    {{ .Title }}

    {{ $inner := trim .RawContent " \n\r" }} {{ if gt (len $inner) 0 }} {{ partial "utilities/ProcessContent" (dict "page" .Page "raw" $inner) }} {{ end }}

    {{ end }} ================================================ FILE: layouts/header.html ================================================ {{/* Initialize global variables */}} {{- $size := .Site.Params.style.title.size | default 4 -}} {{- $headingStyle := .Site.Params.style.title.headingStyle | default "display" -}} {{- $contentStyle := .Site.Params.style.title.contentStyle | default "lead text-muted" -}} {{- $padding := partial "utilities/GetPadding.html" -}} {{- $sharing := .Scratch.Get "sharing" -}} {{/* Initialize local variables */}} {{- $breakpoint := .Scratch.Get "breakpoint" -}} {{ $title := .Title }} {{ if and .Site.Params.main.titleCase (not .Params.exact) }}{{ $title = title $title }}{{ end }} {{/* Render breadcrumb */}} {{ if .Site.Params.navigation.breadcrumb }}{{ partial "assets/breadcrumb.html" (dict "page" .) }}{{ end -}} {{/* Display title and metadata */}} {{ with $title }}

    {{ . }}

    {{ end }} {{/* Render metadata */}} {{- partial "page/metadata.html" . -}} {{/* Render tags */}} {{- partial "page/tags.html" . -}} {{/* Display social sharing buttons */}} {{- if $sharing }}
    {{ partial "page/sharing.html" . }}
    {{ end -}} {{/* Display description */}} {{ with .Description }}
    {{ . | $.RenderString | safeHTML }}
    {{ end }} {{/* Display TOC dropdown on smaller screens */}} {{- if and .Site.Params.navigation.toc .Params.includeToc | default true -}}
    {{ partial "assets/toc-dropdown.html" (dict "page" .) }}
    {{- end -}} ================================================ FILE: layouts/index.redir ================================================ {{- range .Site.Params.docs.releases -}} {{- if .redirect -}} {{ urls.JoinPath .url "/*" }} {{ urls.JoinPath .redirect ":splat" }} 200 {{ end }} {{- end -}} {{ range $p := .Site.AllPages }} {{- range .Aliases -}} {{ if hasPrefix . "." }}{{ urls.JoinPath $p.RelPermalink . }}{{ else }}{{ . }}{{ end }} {{ $p.RelPermalink }} {{ end }} {{- end -}} ================================================ FILE: layouts/list.html ================================================ {{ define "main" -}} {{- $breakpoint := $.Scratch.Get "breakpoint" -}} {{- $padding := partial "utilities/GetPadding.html" -}} {{- $content := partial "utilities/ProcessContent" (dict "page" .Page "raw" .RawContent) }} {{ if .Params.content_blocks }} {{- partial "page/blocks.html" . -}} {{ else }} {{ with partial "page/articles.html" . }}
    {{ . | safeHTML }}
    {{ end }} {{ end }} {{ with $content }}
    {{ . }}
    {{ end }} {{ end -}} ================================================ FILE: layouts/minimal/body.html ================================================ {{ partial "utilities/ProcessContent" (dict "page" .Page "raw" .RawContent) }} ================================================ FILE: layouts/minimal/footer.html ================================================ {{/* Intentionally left blank to suppress page navigation */}} ================================================ FILE: layouts/minimal/header.html ================================================ {{/* Initialize global variables */}} {{- $size := .Site.Params.style.title.size | default 4 -}} {{- $headingStyle := .Site.Params.style.title.headingStyle | default "display" -}} {{- $contentStyle := .Site.Params.style.title.contentStyle | default "lead text-muted" -}} {{- $padding := partial "utilities/GetPadding.html" -}} {{/* Initialize local variables */}} {{- $breakpoint := .Scratch.Get "breakpoint" -}} {{ $title := .Title }} {{ if and .Site.Params.main.titleCase (not .Params.exact) }}{{ $title = title $title }}{{ end }} {{/* Display title */}} {{ with $title }}

    {{ . }}

    {{ end }} {{/* Display description */}} {{ with .Description }}
    {{ . | $.RenderString | safeHTML }}
    {{ end }} ================================================ FILE: layouts/robots.txt ================================================ User-agent: * Allow: / Sitemap: {{ urls.JoinPath .Site.BaseURL "sitemap.xml" }} ================================================ FILE: layouts/single.html ================================================ {{ define "main" -}} {{- $breakpoint := $.Scratch.Get "breakpoint" -}} {{- $padding := partial "utilities/GetPadding.html" -}} {{- $sidebar := partial "page/sidebar" . -}} {{/* Render the offcanvas sidebar and content blocks */}} {{- partial "page/sidebar-offcanvas.html" (dict "section" $.Section "raw" $sidebar) -}} {{- partial "page/blocks.html" . -}} {{/* Render the single page content using responsive columns */}} {{/* Column 1: sidebar navigation, visible in medium viewports and above (uses offcanvas on small devices) */}} {{/* Column 2: main page content (header, body, footer), always visible */}} {{/* Column 3: sharing buttons and TOC navigation or specials (CTA), visible in large viewports */}} {{/* content is folded into main column (handled by page elements) */}} {{ if (gt (len .RawContent) 0) }}
    {{ .Render "header" }} {{ .Render "body" }} {{ .Render "footer" }}
    {{ .Render "toc" }}
    {{ end }} {{ end -}} ================================================ FILE: layouts/single.xml ================================================ {{ define "main" }} {{ with resources.Get "img/favicon.png" }} {{ $square70 := .Resize "70x70 CatmullRom" }} {{ $square150 := .Resize "150x150 CatmullRom" }} {{ $wide310 := .Fill "310x150 CatmullRom" }} {{ $square310 := .Resize "310x310 CatmullRom" }} {{ end }} #000000 {{ end }} ================================================ FILE: layouts/tags/list.html ================================================ {{ define "main" }} {{- $page := . -}} {{- $layout := $page.Params.layout -}} {{- $breakpoint := $.Scratch.Get "breakpoint" -}} {{- $padding := partial "utilities/GetPadding.html" -}} {{- $pageTitle := .Page.Title }} {{ if and site.Params.main.titleCase (not .Page.Params.exact) }}{{ $pageTitle = title $pageTitle }}{{ end }}
    {{- if ne $layout "featured" -}} {{ if and (not $page.IsHome) site.Params.navigation.breadcrumb }}
    {{ partial "assets/breadcrumb.html" (dict "page" $page) }}
    {{ end -}} {{- end -}}

    {{ $pageTitle }}

    {{ if eq .Kind "taxonomy" }} {{- partial "page/taxonomy-list.html" . -}} {{ else }} {{- partial "page/taxonomy-tag.html" . -}} {{ end }}
    {{ end }} ================================================ FILE: layouts/toc.html ================================================ {{- $download := .Params.download -}} {{- $includeToc := .Scratch.Get "includeToc" -}} {{ if or $download $includeToc }}
    {{ if $download }}
    {{ partial "assets/download.html" (dict "download" $download "outline" true "button-size" "sm" "order" "last" ) }}
    {{ end }} {{ if $includeToc }} {{ $index := partial "assets/toc.html" (dict "page" .) }} {{ $index | safeHTML }} {{ end -}}
    {{ end }} ================================================ FILE: netlify.toml ================================================ # Auto-generated file - do not modify [build] command = 'HUGO_HINODE_VERSION=$(git describe --tags $(git rev-list --tags --max-count=1)) npm run build:example' publish = 'exampleSite/public' [build.environment] DART_SASS_VERSION = '1.98.0' HUGO_ENABLEGITINFO = 'true' HUGO_ENV = 'production' HUGO_VERSION = '0.153.1' NODE_VERSION = '24.12.0' NPM_VERSION = '11.6.2' [context] [context.branch-deploy] command = 'HUGO_HINODE_VERSION=$(git describe --tags $(git rev-list --tags --max-count=1)) npm run build:example -- -b $DEPLOY_PRIME_URL' [context.deploy-preview] command = 'HUGO_HINODE_VERSION=$(git describe --tags $(git rev-list --tags --max-count=1)) npm run build:example -- -b $DEPLOY_PRIME_URL' [dev] autoLaunch = false command = 'HUGO_HINODE_VERSION=$(git describe --tags $(git rev-list --tags --max-count=1)) npm run start:example' framework = '#custom' port = 8888 publish = 'public' targetPort = 1313 [[plugins]] package = 'netlify-plugin-hugo-cache-resources' [[headers]] for = '/**' [headers.values] Access-Control-Allow-Origin = '*' Content-Security-Policy = """ base-uri 'self'; \ connect-src 'self' *.analytics.google.com *.google.com *.google-analytics.com *.googletagmanager.com; \ default-src 'none'; \ font-src 'self' fonts.gstatic.com data:; \ form-action 'self'; \ frame-ancestors 'self'; \ frame-src *.googletagmanager.com player.cloudinary.com www.youtube-nocookie.com www.youtube.com player.vimeo.com; \ img-src 'self' *.google-analytics.com *.googletagmanager.com googletagmanager.com ssl.gstatic.com www.gstatic.com data: *.imgix.net *.imagekit.io *.cloudinary.com i.ytimg.com tile.openstreetmap.org i.vimeocdn.com; \ manifest-src 'self'; \ media-src 'self'; \ object-src 'none'; \ script-src 'self' *.google-analytics.com *.googletagmanager.com *.analytics.google.com googletagmanager.com tagmanager.google.com player.vimeo.com; \ style-src 'self' googletagmanager.com tagmanager.google.com fonts.googleapis.com www.youtube.com 'unsafe-inline'; \ """ Permissions-Policy = 'geolocation=(), midi=(), sync-xhr=(), microphone=(), camera=(), magnetometer=(), gyroscope=(), fullscreen=(), payment=() ' Referrer-Policy = 'strict-origin' Strict-Transport-Security = 'max-age=31536000; includeSubDomains; preload' X-Content-Type-Options = 'nosniff' X-XSS-Protection = '1; mode=block' cache-control = 'max-age=0, no-cache, no-store, must-revalidate ' ================================================ FILE: package.json ================================================ { "name": "@gethinode/hinode", "version": "0.0.0-semantically-released", "description": "Hinode is a production-ready Hugo theme built on Bootstrap 5. Open source, actively maintained, and built for developers.", "keywords": [ "hugo", "theme", "bootstrap", "responsive", "front-end", "blog", "documentation" ], "main": "index.js", "private": false, "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" }, "scripts": { "prestart": "npm run -s mod:vendor", "start": "hugo server --bind=0.0.0.0 --disableFastRender --printI18nWarnings", "start:example": "npm run -s prestart && hugo server --bind=0.0.0.0 --disableFastRender --printI18nWarnings -s exampleSite", "start:prod": "npm run -s prestart && hugo server --bind=0.0.0.0 --disableFastRender --printI18nWarnings --minify -e production", "start:example:prod": "npm run -s prestart && hugo server --bind=0.0.0.0 --disableFastRender --printI18nWarnings --minify -e production -s exampleSite", "prebuild": "npm run clean:public && npm run -s mod:vendor", "build": "hugo --gc --minify", "build:cache": "npm run -s prebuild && hugo config | grep cachedir && hugo --gc --minify -e ci", "build:example": "npm run -s prebuild && hugo --gc --minify -s exampleSite", "build:example:ci": "npm run -s prebuild && hugo --gc --minify -s exampleSite -e ci", "build:debug": "hugo -e debug --debug", "build:headers": "npm run build:headers:dev && npm run build:headers:prod", "build:headers:dev": "hugo --renderSegments headers -d prebuild-headers-dev -e development && cpy prebuild-headers-dev/server.toml config/_default/ --flat", "build:headers:prod": "hugo --renderSegments headers -d prebuild-headers-prod -e production && cpy prebuild-headers-prod/netlify.toml ./ --flat", "build:example:headers": "hugo -s exampleSite --renderSegments headers -d prebuild && cpy exampleSite/prebuild/netlify.toml ./ --flat && cpy exampleSite/prebuild/server.toml exampleSite/config/_default/ --flat", "build:preview": "npm run build -D -F", "clean:public": "rimraf public exampleSite/public", "clean:install": "rimraf package-lock.json node_modules", "lint": "npm-run-all lint:**", "lint:scripts": "eslint assets/js --no-error-on-unmatched-pattern", "lint:styles": "stylelint \"assets/scss/**/*.{css,sass,scss,sss,less}\" --allow-empty-input", "lint:markdown": "markdownlint-cli2 \"*.md\" \"content/**/*.md\" \"exampleSite/**/*.md\"", "mod:clean": "hugo mod clean", "mod:update": "rimraf _vendor && hugo mod get -u ./... && npm run -s mod:vendor && npm run -s mod:tidy", "mod:tidy": "hugo mod tidy && hugo mod tidy -s exampleSite", "mod:vendor": "rimraf _vendor && hugo mod vendor", "test": "npm run -s lint", "env": "hugo env", "precheck": "npm version", "prepare": "node .husky/install.mjs", "check": "hugo version", "create:syntax": "npm-run-all update:syntax:**", "update:syntax:light1": "hugo gen chromastyles --style=github > ./assets/scss/components/_syntax-light.scss", "update:syntax:light2": "replace-in-files --string=\"#0086b3\" --replacement=\"#006b8f\" ./assets/scss/components/_syntax-light.scss", "update:syntax:light3": "replace-in-files --string=\"#009999\" --replacement=\"#007a7a\" ./assets/scss/components/_syntax-light.scss", "update:syntax:light4": "replace-in-files --string=\"#999988\" --replacement=\"#6d6d5d\" ./assets/scss/components/_syntax-light.scss", "update:syntax:dark1": "hugo gen chromastyles --style=github-dark > ./assets/scss/components/_syntax-dark.scss", "update:syntax:dark2": "replace-in-files --string=\"#ffffcc\" --replacement=\"#373700\" ./assets/scss/components/_syntax-dark.scss", "update:syntax:dark3": "replace-in-files --string=\"#8b949e\" --replacement=\"#979fa8\" ./assets/scss/components/_syntax-dark.scss", "update:syntax:dark4": "replace-in-files --string=\".na { }\" --replacement=\".na { color: #00cccc }\" ./assets/scss/components/_syntax-dark.scss", "update:syntax:dark5": "replace-in-files --string=\".nb { }\" --replacement=\".nb { color: #00a2d8 }\" ./assets/scss/components/_syntax-dark.scss", "update:syntax:dark6": "replace-in-files --string=\"#6e7681\" --replacement=\"#999fa8\" ./assets/scss/components/_syntax-dark.scss", "upgrade": "npx npm-check-updates -u && npm run -s mod:update" }, "repository": { "type": "git", "url": "git+https://github.com/gethinode/hinode.git" }, "author": "Mark Dumay", "license": "MIT", "bugs": { "url": "https://github.com/gethinode/hinode/issues" }, "homepage": "https://gethinode.com", "dependencies": { "@fullhuman/postcss-purgecss": "^8.0.0", "autoprefixer": "^10.5.0", "cssnano": "^8.0.0", "cssnano-preset-advanced": "^8.0.0", "hugo-extended": "^0.161.1", "postcss-cli": "^11.0.1", "rimraf": "^6.1.3" }, "devDependencies": { "@commitlint/cli": "^21.0.0", "@commitlint/config-conventional": "^21.0.0", "@eslint/js": "^10.0.1", "@semantic-release/exec": "^7.1.0", "@semantic-release/git": "^10.0.1", "@stylistic/eslint-plugin": "^5.10.0", "cpy-cli": "^7.0.0", "cz-conventional-changelog": "^3.3.0", "eslint": "^10.3.0", "globals": "^17.6.0", "husky": "^9.1.7", "markdownlint-cli2": "^0.22.1", "netlify-plugin-hugo-cache-resources": "^0.2.1", "npm-run-all": "^4.1.5", "replace-in-files-cli": "^4.0.0", "semantic-release": "^25.0.3", "shx": "^0.4.0", "stylelint": "^17.11.0", "stylelint-config-standard-scss": "^17.0.0" }, "optionalDependencies": { "fsevents": "*" }, "release": { "branches": [ "main", { "name": "beta", "prerelease": true } ], "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", "@semantic-release/github", [ "@semantic-release/exec", { "prepare": "npm install" } ], [ "@semantic-release/git", { "assets": [ "dist", "package.json", "package-lock.json" ], "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" } ] ] } } ================================================ FILE: static/js/alias.js ================================================ const alias = document.querySelector("link[rel='canonical']").getAttribute('href') const params = window.location.search + window.location.hash window.location = alias + params ================================================ FILE: theme.toml ================================================ name = "Hinode" license = "MIT" licenselink = "https://github.com/gethinode/hinode/blob/main/LICENSE" description = "A clean documentation and blog theme for your Hugo site based on Bootstrap 5." homepage = "https://gethinode.com" tags = ["blog", "documentation", "minimal", "modern", "customizable", "search", "bootstrap"] features = ["security aware", "fast by default", "seo-ready", "development tools", "bootstrap framework", "netlify-ready", "full text search", "page layouts", "versioned documentation"] min_version = "0.146.0" [author] name = "Mark Dumay" homepage = "https://github.com/markdumay"