forked from github/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcode-header.js
More file actions
84 lines (76 loc) · 2.38 KB
/
code-header.js
File metadata and controls
84 lines (76 loc) · 2.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/**
* Adds a bar above code blocks that shows the language and a copy button
*/
import yaml from 'js-yaml'
import fs from 'fs'
import { visit } from 'unist-util-visit'
import { h } from 'hastscript'
import octicons from '@primer/octicons'
import { parse } from 'parse5'
import { fromParse5 } from 'hast-util-from-parse5'
import murmur from 'imurmurhash'
const languages = yaml.load(fs.readFileSync('./data/code-languages.yml', 'utf8'))
const matcher = (node) =>
node.type === 'element' &&
node.tagName === 'pre' &&
// For now, limit to ones with the copy meta,
// but we may enable for all examples later.
getPreMeta(node).copy &&
// Don't add this header for annotated examples.
!getPreMeta(node).annotate
export default function codeHeader() {
return (tree) => {
visit(tree, matcher, (node, index, parent) => {
parent.children[index] = wrapCodeExample(node)
})
}
}
function wrapCodeExample(node) {
const lang = node.children[0].properties.className?.[0].replace('language-', '')
const code = node.children[0].children[0].value
return h('div', { className: 'code-example' }, [header(lang, code), node])
}
export function header(lang, code, subnav) {
const codeId = murmur('js-btn-copy').hash(code).result()
return h(
'header',
{
class: [
'd-flex',
'flex-items-center',
'flex-justify-between',
'p-2',
'text-small',
'rounded-top-1',
'border-top',
'border-left',
'border-right',
],
},
[
h('span', { className: 'flex-1' }, languages[lang]?.name),
subnav,
h(
'button',
{
class: ['js-btn-copy', 'btn', 'btn-sm', 'tooltipped', 'tooltipped-nw'],
'aria-label': `Copy ${languages[lang]?.name} code to clipboard`,
'data-clipboard': codeId,
},
btnIcon(),
),
h('pre', { hidden: true, 'data-clipboard': codeId }, code),
],
)
}
function btnIcon() {
const btnIconHtml = octicons.copy.toSVG()
const btnIconAst = parse(String(btnIconHtml), { sourceCodeLocationInfo: true })
const btnIcon = fromParse5(btnIconAst, { file: btnIconHtml })
return btnIcon
}
function getPreMeta(node) {
// Here's why this monstrosity works:
// https://github.com/syntax-tree/mdast-util-to-hast/blob/c87cd606731c88a27dbce4bfeaab913a9589bf83/lib/handlers/code.js#L40-L42
return node.children[0]?.data?.meta || {}
}