Skip to content
This repository has been archived by the owner on May 3, 2023. It is now read-only.

Add copy button & language name to code blocks #32

Closed
JasonEtco opened this issue Oct 8, 2020 · 2 comments
Closed

Add copy button & language name to code blocks #32

JasonEtco opened this issue Oct 8, 2020 · 2 comments

Comments

@JasonEtco
Copy link

Hello! I'm opening this on behalf of the GitHub Docs team 👋 We'd like to add a copy-to-clipboard button to code fences, automatically as part of the rendering pipeline. One way that we've done this in the past is with a custom Unified plugin

I yoinked this out of another project, but here's some code
import { Node } from 'hast'
import h from 'hastscript'
import octicons from '@primer/octicons'
import parse5 from 'parse5'
import fromParse5 from 'hast-util-from-parse5'

const LANGUAGE_MAP = {
  'asp': 'ASP',
  // ...
}

interface CodeNode extends Node {
  lang: string
  value: string
}

/**
 * Adds a bar above code blocks that shows the language and a copy button
 */
export default function addCodeHeader (node: CodeNode) {
  const language = LANGUAGE_MAP[node.lang] || node.lang || 'Code'

  const btnIconHtml = octicons.clippy.toSVG()
  const btnIconAst = parse5.parse(String(btnIconHtml))
  const btnIcon = fromParse5(btnIconAst, btnIconHtml)

  const header = h('header', 
    {
      class: [
        'd-flex',
        'flex-items-center',
        'flex-justify-between',
        'p-2',
        'text-small',
        'rounded-top-1',
        'border'
      ]
    }, [
    h('span', language),
    h(
      'button',
      {
        class: ['js-btn-copy', 'btn', 'btn-sm', 'tooltipped', 'tooltipped-nw'],
        ['data-clipboard-text']: node.value,
        ['aria-label']: 'Copy code to clipboard'
      },
      btnIcon
    )
  ])

  return {
    before: [header]
  }
}

That generates a <header> that looks like this:

The actual copy-to-clipboard functionality is handled by some delegated events, but it doesn't have to be.

I'd love to add this kind of functionality here in hubdown, but there are a couple of decisions to be made, all of which are pretty specific to our use-case. So for us to add this to the render pipeline for github/docs, we have to:

  • Add this plugin to hubdown's createProcessor, which may cause unwanted changes to other consumers like Electron's docs
  • Fork (and maintain our fork of) hubdown, which is also not ideal
  • Export createProcessor from hubdown, and inject this one plugin at a particular point to it

Wondering if y'all have any thoughts on the right approach here. Is this feature something you've wanted in the past? I'm happy to work with y'all to make it useful for both Electron and docs.github.com!

@MarshallOfSound
Copy link
Member

Discussed in DM, but for SEO reasons 😆 The beforeRun option should allow folks to add custom plugins to the processor.

@JasonEtco
Copy link
Author

It's true, it does! Thanks @MarshallOfSound, you tha best ❤️

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants