Ctrl K
ComunidadGuías…

overrides/main.html

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
{#
  Sharing and search metadata for zoomies.sh.

  Material's own social plugin is not used: it renders a card image per page
  with Cairo and Pillow, which would put two native libraries into the docs
  build for a picture the brand pack already supplies. These blocks are the part
  that matters -- a title, a description, one card image, and a machine-readable
  description of what the project is, absolute, on every page -- and they cost
  nothing.

  Everything here is derived from the page rather than written twice: the
  description falls back to site_description, the canonical URL is the one
  MkDocs already computes, the breadcrumb is read out of the navigation, and the
  modified date comes from git by way of hooks/seo.py.
#}
{% extends "base.html" %}
{% from "partials/icons-zoomies.html" import icon %}
{% set layout = page.meta.layout if page else "notfound" %}

{#
  Locally hosted faces, so the page makes no third-party font request. Material
  would otherwise put a Google Fonts stylesheet in the head, and a
  render-blocking request to a host the reader cannot reach is what left the tab
  spinning with nothing to show. The @font-face rules and the woff2 files live
  in stylesheets/ beside this theme's CSS.
#}
{% block fonts %}
  <style>:root{--md-text-font:"Plex";--md-code-font:"PlexMono"}</style>
  <link rel="preload" href="{{ 'stylesheets/fonts/showcase/fraunces-latin-600-normal.woff2' | url }}" as="font" type="font/woff2" crossorigin>
{% endblock %}

{#
  The home page's title in a search result. Its heading is the tagline, written
  to be read under the logo, and Material would put that in the tab and the
  result too -- "Give your GitHub Actions runners the Zoomies." says nothing to
  someone searching for self-hosted runners. The social_title already says what
  Zoomies is, so the result uses it as well. Every other page keeps Material's
  rule: its own title, then the site's name.
#}
{% block htmltitle %}
  {% if page and page.is_homepage and page.meta and page.meta.social_title %}
    <title>{{ page.meta.social_title }}</title>
  {% elif page and not page.is_homepage and page.title and config.site_name in (page.meta.title or page.title) %}
    {# The theme appends the site's name; a title that already says it does not need it twice. #}
    <title>{{ page.meta.title or page.title }}</title>
  {% else %}
    {{ super() }}
  {% endif %}
{% endblock %}

{% block extrahead %}
  {#
    The full-width layouts have no sidebar on a desktop screen. The rule that
    hides it in showcase-material.css is `:has(> .site-home)`, and the sidebar
    comes before the content in the markup, so while the browser is still
    parsing the page that selector has nothing to match and the unstyled
    navigation flashes on the left of a blank page. The layout is known here, in
    the head, before any of the body arrives, so say it plainly instead of
    waiting for the parser to find out.
  #}
  {% if layout in ['home', 'hub', 'guides', 'compare', 'article'] %}
  <style>@media (min-width:76.25em){.md-sidebar[id=zoomies-navigation]{display:none}}</style>
  {% endif %}
  {#
    Cloudflare Web Analytics: a cookieless page-view counter that sets nothing
    on the reader's device and keeps no per-visitor profile. It is the only
    third-party script the site loads, so docs/privacy.md names it and
    site-worker/worker.js allows exactly its two origins and no others. The
    token identifies the site and is public by design.
  #}
  <script defer src="https://static.cloudflareinsights.com/beacon.min.js"
          data-cf-beacon='{"token": "0c3c36183dc3e0714e8de12c040ba3d5"}'></script>
  {#
    The page's own title, not the abbreviation the sidebar uses: a navigation
    entry is trimmed to fit a column, and "FAQ -- Zoomies" is a worse thing to
    find in a search result than the sentence the page opens with.
  #}
  {% set page_title = (page.meta.title if page and page.meta and page.meta.title else (page.title if page else none)) %}
  {% set title = config.site_name %}
  {% if page_title and not page.is_homepage %}
    {# A title that already names the product does not repeat it: "Zoomies vs Cirun - Zoomies" spends a fifth of its length on one word. #}
    {% set title = page_title if config.site_name in page_title else page_title ~ " - " ~ config.site_name %}
  {% endif %}
  {#
    A page may name the title it wants to be shared under. The home page needs
    one: its heading is written to be read on the page, where the logo is
    already above it, and a link pasted into a chat window has neither. Anything
    else falls back to the rule above.
  #}
  {% if page and page.meta and page.meta.social_title %}
    {% set title = page.meta.social_title %}
  {% endif %}
  {% set description = config.site_description %}
  {% if page and page.meta and page.meta.description %}
    {% set description = page.meta.description %}
  {% endif %}
  {% set image = config.site_url ~ "brand/social-card.png" %}
  {% set canonical = page.canonical_url if page else config.site_url %}
  {% set modified = page.meta.git_date if page and page.meta else none %}

  {#
    Everything here is public documentation and is meant to be found, so the
    directives are the permissive ones: a full snippet rather than the ~160
    characters a search engine otherwise truncates to, and a large preview
    image rather than a thumbnail.

    The exceptions are the 404 template, which has no page behind it and is
    rendered at a different address every time it is served, and a page whose
    front matter says `noindex: true` -- notes written for contributors, which
    are published so links to them work but are not an answer to anything
    someone searches for. overrides/sitemap.xml leaves those out too.
  #}
  {% if page and not (page.meta and page.meta.noindex) %}
  <meta name="robots" content="index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1" />
  {% else %}
  <meta name="robots" content="noindex, follow" />
  {% endif %}

  {#
    The theme's `favicon` setting emits only the .ico. The paw/swish SVG swaps
    colour with the browser's scheme, which a tab on a dark toolbar needs and
    an .ico cannot do; the touch icon and manifest are what a phone's home
    screen and an Android toolbar read. They are the icons the product's own UI
    ships, so the site and the app look like one thing.
  #}
  <link rel="icon" href="{{ config.site_url }}favicon.svg" type="image/svg+xml" />
  <link rel="apple-touch-icon" href="{{ config.site_url }}apple-touch-icon.png" />
  <link rel="manifest" href="{{ config.site_url }}site.webmanifest" />

  <meta property="og:type" content="{{ 'article' if page and not page.is_homepage else 'website' }}" />
  <meta property="og:locale" content="en_GB" />
  <meta property="og:site_name" content="{{ config.site_name }}" />
  <meta property="og:title" content="{{ title }}" />
  <meta property="og:description" content="{{ description | striptags | trim }}" />
  <meta property="og:url" content="{{ canonical }}" />
  {#
    The page as Markdown, for an assistant that would rather read the source
    than the theme. hooks/seo.py writes the copy beside the page, and a 404
    has no page and so no copy.
  #}
  {% if page and page.file %}<link rel="alternate" type="text/markdown" href="{{ canonical }}index.md" />{% endif %}
  {#
    RFC 9727's api-catalog link relation and the ai-catalog index it names,
    for a reader that parses a page's head rather than its Link headers. The
    api-catalog well-known document and the header the site worker adds come
    from the same generated files as these.
  #}
  <link rel="api-catalog" href="/.well-known/api-catalog" />
  <link rel="ai-catalog" href="/.well-known/ai-catalog.json" />
  <meta property="og:image" content="{{ image }}" />
  <meta property="og:image:secure_url" content="{{ image }}" />
  <meta property="og:image:type" content="image/png" />
  <meta property="og:image:width" content="1200" />
  <meta property="og:image:height" content="630" />
  <meta property="og:image:alt" content="The Zoomies logo: a running cocker spaniel inside a circular swish" />
  {% if modified %}
  <meta property="article:modified_time" content="{{ modified }}" />
  {% endif %}
  <meta name="twitter:card" content="summary_large_image" />
  <meta name="twitter:title" content="{{ title }}" />
  <meta name="twitter:description" content="{{ description | striptags | trim }}" />
  <meta name="twitter:image" content="{{ image }}" />
  <meta name="twitter:image:alt" content="The Zoomies logo: a running cocker spaniel inside a circular swish" />

  {#
    The structured description search engines and AI assistants read. It says
    what Zoomies is, what it runs on and what it costs, because those are the
    three questions someone asks before installing a runner controller.

    It is on the home page only. Repeating one application's description on
    every page of its documentation is how a site ends up with fifteen
    competing answers to "what is this".

    The WebSite entry beside it names the site. It deliberately carries no
    SearchAction: Google retired the sitelinks search box, and advertising a
    ?q= template made crawlers fetch one address per page with a query on the
    end, which Search Console then reports as alternates of the page.
  #}
  {% if page and page.is_homepage %}
  <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      "@graph": [
        {
          "@type": "SoftwareApplication",
          "@id": "{{ config.site_url }}#software",
          "name": "Zoomies",
          "alternateName": "Zoomies runner fleet controller",
          "applicationCategory": "DeveloperApplication",
          "applicationSubCategory": "Continuous integration",
          "operatingSystem": "Linux",
          "url": "{{ config.site_url }}",
          "downloadUrl": "{{ config.site_url }}quickstart/",
          "installUrl": "{{ config.site_url }}install.sh",
          "codeRepository": "{{ config.repo_url }}",
          "license": "https://www.gnu.org/licenses/agpl-3.0.html",
          "description": {{ description | striptags | trim | tojson }},
          "image": "{{ image }}",
          "featureList": [
            "Ephemeral runners, one job per container",
            "GitHub App authentication with single-use JIT registrations",
            "Webhook-driven autoscaling, with polling as a fallback",
            "Multi-host agents that connect outbound only",
            "A live web UI for the whole fleet, with Prometheus metrics and an audit log",
            "Runner images for Ubuntu, Debian, Fedora and Rocky Linux",
            "A migration wizard that rewrites runs-on and opens one pull request per repository",
            "A one-line installer"
          ],
          "offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" },
          "isAccessibleForFree": true,
          "author": { "@id": "{{ config.site_url }}#org" },
          "publisher": { "@id": "{{ config.site_url }}#org" },
          "keywords": "self-hosted GitHub Actions runner, ephemeral runners, autoscaling CI runners, GitHub Actions runner controller, self-hosted CI"
        },
        {
          "@type": "Organization",
          "@id": "{{ config.site_url }}#org",
          "name": "Zoomies",
          "legalName": "Zoomies contributors",
          "url": "{{ config.site_url }}",
          "logo": "{{ config.site_url }}brand/github-avatar.png",
          "sameAs": ["{{ config.repo_url }}"]
        },
        {
          "@type": "WebSite",
          "@id": "{{ config.site_url }}#website",
          "publisher": { "@id": "{{ config.site_url }}#org" },
          "url": "{{ config.site_url }}",
          "name": "{{ config.site_name }}",
          "description": {{ description | striptags | trim | tojson }},
          "inLanguage": "en-GB",
          "about": { "@id": "{{ config.site_url }}#software" }
        }
      ]
    }
  </script>
  {% elif page %}
  {#
    A documentation page describes itself, and says where it sits. The
    breadcrumb is read out of the navigation rather than the URL, so a page
    moved between sections in mkdocs.yml moves here too.
  #}
  {#
    The home page's @graph is the only place the entities are defined, and a
    crawler reads one page at a time: an @id that points at another page's
    graph resolves to nothing. So each article carries a small copy of what it
    names, with the same @id so a consumer that does merge them can.
  #}
  <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      "@type": "TechArticle",
      "headline": {{ page_title | tojson }},
      "description": {{ description | striptags | trim | tojson }},
      "url": "{{ canonical }}",
      "inLanguage": "en-GB",
      {% if modified %}"dateModified": "{{ modified }}",{% endif %}
      "image": "{{ image }}",
      "isPartOf": { "@type": "WebSite", "@id": "{{ config.site_url }}#website", "name": "{{ config.site_name }}", "url": "{{ config.site_url }}" },
      "about": { "@type": "SoftwareApplication", "@id": "{{ config.site_url }}#software", "name": "Zoomies", "url": "{{ config.site_url }}" },
      "author": { "@type": "Organization", "@id": "{{ config.site_url }}#org", "name": "Zoomies", "url": "{{ config.site_url }}", "sameAs": ["{{ config.repo_url }}"] },
      "publisher": { "@type": "Organization", "@id": "{{ config.site_url }}#org", "name": "Zoomies", "url": "{{ config.site_url }}", "sameAs": ["{{ config.repo_url }}"] },
      "license": "https://www.gnu.org/licenses/agpl-3.0.html"
    }
  </script>
  <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      "@type": "BreadcrumbList",
      "itemListElement": [
        { "@type": "ListItem", "position": 1, "name": "Home", "item": "{{ config.site_url }}" }
        {%- set linked_ancestors = page.ancestors | reverse | selectattr('url') | list -%}
        {%- for parent in linked_ancestors %}
        , { "@type": "ListItem", "position": {{ loop.index + 1 }}, "name": {{ parent.title | tojson }}, "item": {{ (config.site_url ~ parent.url) | tojson }} }
        {%- endfor %}
        , { "@type": "ListItem", "position": {{ linked_ancestors | length + 2 }}, "name": {{ page_title | tojson }}, "item": "{{ canonical }}" }
      ]
    }
   </script>
  {% endif %}

  <script>
    // WebMCP (draft): the tool an agentified browser finds on this page. The
    // page is Markdown underneath (hooks/seo.py writes the copy the theme's
    // alternate link above names), so a registrant that would rather read the
    // source than the theme asks for one identical thing, and the browser
    // Agent can fetch it from where it already sits. registerTool and
    // modelContext exist only in browsers that have the API: without one the
    // script is a no-op, so a person's browser does nothing different.
    (function () {
      if (document.modelContext || navigator.modelContext) {
        var context = document.modelContext || navigator.modelContext;
        var copy = document.querySelector('link[rel="alternate"][type="text/markdown"]');
        if (copy) {
          var address = copy.getAttribute("href");
          context.registerTool({
            name: "read_page_as_markdown",
            description: "The current page as the Markdown source it was written in, without the site's navigation, footer or icons",
            inputSchema: { type: "object", properties: {} },
            execute: async function () {
              var response = await fetch(address);
              if (!response.ok) {
                throw new Error("the Markdown copy answered " + response.status);
              }
              return await response.text();
            },
          }).catch(function () {});
        }
      }
    })();
  </script>
{% endblock %}


{% block tabs %}{% endblock %}
{% block scripts %}
  {% if page and ('class="mermaid"' in page.content or page.meta.pack_diagram) %}
    <script src="{{ config.extra.showcase_mermaid | url }}"></script>
  {% endif %}
  {{ super() }}
{% endblock %}
{% block site_nav %}
  <div id="zoomies-navigation" class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation">
    <div class="md-sidebar__scrollwrap"><div class="md-sidebar__inner">{% include "partials/nav.html" %}</div></div>
  </div>
  {% if layout not in ['home', 'hub', 'guides', 'compare', 'article'] %}
    <div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc"><div class="md-sidebar__scrollwrap"><div class="md-sidebar__inner">{% include "partials/toc.html" %}</div></div></div>
  {% endif %}
{% endblock %}

{% block container %}
  {% if layout in ['home', 'hub', 'guides', 'compare'] %}
    <div class="site-{{ layout }}" data-md-component="content" id="main" tabindex="-1">{% include "partials/showcase-" ~ layout ~ ".html" %}</div>
  {% elif layout == 'article' %}
    <div class="site-article" data-md-component="content" id="main" tabindex="-1">{% include "partials/field-article.html" %}</div>
  {% else %}
    <div class="md-content z-doc" data-md-component="content" id="main" tabindex="-1"><article class="md-content__inner md-typeset">
      {% if page %}{% include "partials/crumbs-zoomies.html" %}<div class="eyebrow">The Zoomies handbook</div>{% endif %}
      {% block content %}{% include "partials/content.html" %}{% endblock %}
      {% if page %}{% include "partials/page-tools-zoomies.html" %}{% endif %}
    </article></div>
  {% endif %}
{% endblock %}