Copier en Markdown

Le bouton Copier en Markdown permet au lecteur de copier l’article canonique en Markdown plutôt que de coller du HTML rendu dans une invite. Le modèle suit le bouton Copy as Markdown de thoughtbot et convient à ces sites parce que la source de vérité est déjà en Markdown : les articles doivent être faciles à lire dans un navigateur, mais aussi faciles à remettre à un assistant, à citer dans une note de travail ou à archiver en texte brut.

Le bouton ci-dessous est le composant en direct; il copie la sortie Markdown de cette page dans le presse-papiers et remplace brièvement son libellé par « Copié ».

Quand l’utiliser#

  • Les pages d’articles — billets de blogue et notes AJA — reçoivent le bouton automatiquement dans l’entête de page; il n’y a rien à déclarer par page
  • La lectrice ou le lecteur doit pouvoir remettre l’article canonique à un assistant, le citer dans une note de travail ou l’archiver en texte brut
  • La fonction n’exige ni compte, ni API, ni intégration spéciale : une version durable en texte brut de la page et un bouton pour les lecteurs qui veulent le Markdown directement
  • Une page hors des sections blogue et AJA peut forcer le bouton avec showCopyMarkdown sous la clé de front matter pageHeader
  • Sur les pages de blogue et AJA, l’entête HTML annonce aussi la représentation Markdown aux machines, qu’un lecteur appuie sur le bouton ou non

Implémentation#

La configuration du site enregistre la sortie, et chaque page régulière la rend :

mediaTypes:
  text/markdown:
    suffixes:
      - md

outputFormats:
  Markdown:
    mediaType: text/markdown
    rel: alternate
    isPlainText: true
    notAlternative: false

outputs:
  page:
    - HTML
    - Markdown

Le template Markdown, layouts/_default/single.markdown.md, émet un petit bloc de front matter, puis le contenu Markdown brut de la page :

---
title: {{ .Title | jsonify }}
lastmod: {{ .Lastmod.Format "2006-01-02" | jsonify }}
canonical: {{ .Permalink | jsonify }}
---

{{ .RawContent }}

L’entête de page rend le bouton par le partial partagé :

{{ partial "copy-as-markdown.html" $page }}
<button type="button" class="copy-markdown-button" aria-label="Copier en Markdown" title="Copier en Markdown" data-copy-markdown-url="/fr/docs/site-implementation/components/copier-en-markdown/index.md" data-copy-label="Copier en Markdown" data-copied-label="Copié" data-error-label="Copie impossible">
  <img class="copy-markdown-icon copy-markdown-icon-light" src="/images/markdown-mark-solid.svg" alt="" aria-hidden="true" />
  <img class="copy-markdown-icon copy-markdown-icon-dark" src="/images/markdown-mark.svg" alt="" aria-hidden="true" />
  <span class="sr-only" aria-live="polite">Copier en Markdown</span>
</button>

Le gestionnaire est l’écouteur de clic au niveau du document dans assets/js/site.js, lié à [data-copy-markdown-url]. Il récupère cette URL, copie la réponse par l’assistant partagé copyText — le même que la copie des blocs de code, de sorte qu’il n’existe qu’un seul chemin de repli pour les navigateurs plus anciens — et remplace brièvement le libellé, l’aria-label et le title du bouton.

Attribut ou classeRôle
data-copy-markdown-urlURL de la sortie Markdown de la page; aussi ce que le gestionnaire cible
data-copy-labelLibellé au repos, rétabli après le remplacement
data-copied-labelLibellé affiché après une copie réussie
data-error-labelLibellé affiché quand la requête ou la copie échoue
copy-markdown-button-doneClasse basculée en cas de succès
copy-markdown-button-errorClasse basculée en cas d’échec

Le partial partagé est layouts/partials/copy-as-markdown.html. Il ne se rend que lorsque la page a une sortie Markdown, reçoit la vraie URL de sortie de Hugo — le JavaScript n’a donc jamais à deviner si le Markdown vit à post.md ou à post/index.md — et tire ses trois libellés de i18n. layouts/partials/entry-title-block.html active le bouton pour les billets de blogue et les notes AJA, et layouts/_default/baseof.html ajoute <link rel="alternate" type="text/markdown" href="…"> à l’entête HTML de ces pages. Il n’y a pas de feuille de style dédiée; les classes du bouton vivent dans assets/css/site.css.

Manifeste d’interface

Nature
Composant
Catégorie
Action
Statut
Implémenté
Implémentation
Partial:layouts/partials/copy-as-markdown.htmllayouts/partials/entry-title-block.htmlGabarit:layouts/_default/baseof.htmllayouts/_default/single.markdown.mdCSS:assets/css/site.cssJavaScript:assets/js/site.jsi18n:copyAsMarkdowncopiedMarkdowncopyMarkdownErrorConfiguration:config/_default/hugo.yml

Accessibilité#

  • Le contrôle est un <button type="button"> natif : le clic, Entrée et la barre d’espacement l’activent, sans gestion de touches particulière
  • Le bouton à icône seule porte son nom accessible de trois façons : l’aria-label, l’élément <span> masqué visuellement (sr-only) et un title correspondant; les deux icônes sont décoratives, avec un alt vide et aria-hidden="true"
  • L’élément sr-only du libellé porte aria-live="polite" : le passage à « Copié » — ou au libellé d’erreur — est annoncé par les lecteurs d’écran plutôt que montré seulement à l’écran
  • Évitez de traiter les classes copy-markdown-button-done et copy-markdown-button-error comme la rétroaction; ce sont des accroches de style, et c’est le remplacement du libellé qui rend le résultat perceptible