feat(docs): add website icons and social preview metadata - #165
Merged
Conversation
The documentation site shipped no icon assets and only three Open Graph tags, because the atelier project type sets `open-graph: true` and Quarto emits nothing beyond title, description, and site name from that. Add an icon set derived from one hand-authored SVG, a social preview card rendered from a committed Typst template, a web app manifest, and a filter covering the head tags Quarto has no configuration for: `og:type`, a per-page `og:url` and canonical link, `<meta name="description">` from the pandoc `description-meta` variable Quarto never populates, and the icon, manifest, and theme-color links. The Twitter card and `og:locale` are configuration rather than markup: naming `twitter-card` at all is what switches Quarto's provider on. `website.site-url` is anchored and republished as top-level metadata because Quarto keeps the `website` block out of what it hands to Lua filters, so the filter cannot read it to build the canonical URL. `project.resources` is required because Quarto copies nothing to the output directory by convention, and a manifest names its icons in JSON, which is not scanned for resource references. 404.qmd gains a description; it was the only page without one, since every other page carries a subtitle that Quarto already uses as the fallback.
The bundled extensions carry a `--- @module` header with licence, copyright, and author, plus LuaDoc annotations on each function. Bring the configuration-reference filter to the same shape so both filters in the project read alike.
The filter counted path separators to rebuild the offset back to the site root. Quarto already computes that and exposes it as `quarto.project.offset`, which is how it builds its own `website.favicon` href, so the hand-rolled arithmetic was a second implementation of the same thing. Output is identical at the root, in a subdirectory, and on the 404 page. Writing favicon.ico straight from the transparent render made ImageMagick store an uncompressed 32-bit bitmap. Flattening to an opaque PNG first lets it pick a palette: 4,286 bytes down to 2,238, byte-for-byte identical pixels. Typst writes an alpha channel that is opaque everywhere, since the page has a solid fill. Dropping it is lossless and takes the card from 40 KB to 39 KB. Both regeneration recipes are updated so they reproduce what is committed.
The filter added here has shipped in the extension, so the local copy is removed rather than left alongside it. Its configuration moves under `extensions.atelier`, where the anchored `site-url` now lives with the icon, touch icon, manifest, and theme colours. `open-graph.locale` and `twitter-card.card-style` are dropped: the extension sets both, the locale alongside the `lang: en-GB` it already contributes. The site-specific parts stay where they are, since the extension has no opinion on them: the icon artwork, the social card, the manifest contents, `website.image`, `website.image-alt`, `website.favicon`, and the `project.resources` globs that get the files into the output directory. Verified across a full render: 13 pages, no warnings, 13 distinct descriptions, 12 distinct canonical URLs for the 12 non-404 pages, all 52 icon and manifest references and both manifest icons resolving, and every absolute URL carrying the site prefix.
mcanouil
marked this pull request as ready for review
July 26, 2026 19:57
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The documentation site shipped no icon assets and only three Open Graph tags. The atelier project type sets
open-graph: true, and Quarto emits nothing beyond title, description, and site name from that: no image, noog:url, noog:type, no locale, no Twitter card, and no plain<meta name="description">.Adds an icon set derived from one hand-authored SVG at
docs/assets/icons/icon.svg, which carries an inlineprefers-color-schemerule so it flips with the browser theme. The favicon, Apple touch icon, and the two manifest icons are rasterised from it withrsvg-convertandmagick;raster-dark.cssforces the dark variant, since librsvg does not evaluate media queries and the light outline would vanish against the midnight background the rasters use.docs/assets/icons/README.mdrecords the commands.The social card is 1200x630, rendered from
docs/assets/social/og-image.typ, committed so it can be regenerated. It embedsicon-512.pngrather than the SVG because Typst renders SVG through resvg, which ignores the media query.docs/assets/filters/social-metadata.luaemits the head tags Quarto has no configuration key for:og:type, a per-pageog:urland<link rel="canonical">,<meta name="description">via the pandocdescription-metavariable Quarto never populates, and the SVG icon, Apple touch icon, manifest, and theme-color links. Paths are written relative to each page, so they resolve underquarto previewat the server root and under the deployed/quarto-codespaces/prefix alike; Quarto rewrites them to site-absolute paths on404.html, which is served from any depth. The 404 page gets no canonical URL, since it answers for every missing path.The image, image alt, locale, and Twitter card are configuration rather than markup. Naming
twitter-cardat all is what switches Quarto's provider on, after which it inherits title, description, image, and image alt per page.website.site-urlis anchored and republished as top-levelsite-urlbecause Quarto keeps thewebsiteblock out of the metadata it hands to Lua filters, so the filter cannot read it to build the canonical URL.project.resourcesis needed because Quarto copies nothing to the output directory by convention, and a manifest names its icons in JSON, which is not scanned for resource references.404.qmdgains a description. It was the only page without one; the other twelve carry a subtitle, which Quarto already uses as the fallback.Verified against a full render: 13 pages, no warnings, 13 distinct descriptions, every
og:urlunique and absent on the 404, and all 52 icon and manifest references plus the three manifest paths resolving to files in_site.