Skip to content

Commit c3696d2

Browse files
authored
feat: headers badge (#540)
1 parent 4e7f3da commit c3696d2

File tree

9 files changed

+68
-16
lines changed

9 files changed

+68
-16
lines changed

docs/guide/markdown.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ export default {
224224
}
225225
```
226226

227-
## Import Code Snippets
227+
## Import Code Snippets <Badge text="Experimental" type="warn"/> <Badge text="0.0.11+" type="tip"/>
228228

229229
You can import code snippets from existing files via following syntax:
230230

lib/app/app.js

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Vue from 'vue'
22
import Router from 'vue-router'
33
import Content from './Content'
44
import OutboundLink from '../default-theme/OutboundLink.vue'
5+
import Badge from '../default-theme/Badge.vue'
56
import ClientOnly from './ClientOnly'
67
import dataMixin from './dataMixin'
78
import store from './store'
@@ -30,6 +31,7 @@ Vue.mixin(dataMixin(siteData))
3031
// component for rendering markdown content and setting title etc.
3132
Vue.component('Content', Content)
3233
Vue.component('OutboundLink', OutboundLink)
34+
Vue.component('Badge', Badge)
3335
// component for client-only content
3436
Vue.component('ClientOnly', ClientOnly)
3537

lib/default-theme/Badge.vue

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<script>
2+
export default {
3+
functional: true,
4+
props: ['type', 'text'],
5+
render (h, { props, slots }) {
6+
return h('span', {
7+
class: ['badge', props.type]
8+
}, props.text || slots().default)
9+
}
10+
}
11+
</script>
12+
13+
<style lang="stylus">
14+
@import './styles/config.styl'
15+
16+
.badge
17+
display inline-block
18+
vertical-align top
19+
font-size 14px
20+
height 18px
21+
line-height 18px
22+
border-radius 9px
23+
padding 0 5px
24+
color white
25+
margin-right 5px
26+
&.tip
27+
background-color #42b983
28+
&.warning, &.warn
29+
background-color darken(#ffe564, 35%)
30+
</style>

lib/default-theme/styles/theme.styl

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
@require './custom-blocks'
55
@require './arrow'
66
@require './wrapper'
7+
@require './toc'
78

89
html, body
910
padding 0

lib/default-theme/styles/toc.styl

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.table-of-contents
2+
.badge
3+
vertical-align middle

lib/markdown/index.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ const emoji = require('markdown-it-emoji')
1111
const anchor = require('markdown-it-anchor')
1212
const toc = require('markdown-it-table-of-contents')
1313
const _slugify = require('./slugify')
14-
const parseHeaders = require('../util/parseHeaders')
14+
const { parseHeaders, removeTailHtml } = require('../util/parseHeaders')
15+
const { compose } = require('../util/shared')
1516

1617
module.exports = ({ markdown = {}} = {}) => {
1718
// allow user config slugify
18-
const slugify = markdown.slugify || _slugify
19+
const slugify = markdown.slugify || compose(removeTailHtml, _slugify)
1920

2021
const md = require('markdown-it')({
2122
html: true,

lib/util/index.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const parseHeaders = require('./parseHeaders')
1+
const { deeplyParseHeaders } = require('./parseHeaders')
22

33
exports.normalizeHeadTag = function (tag) {
44
if (typeof tag === 'string') {
@@ -32,11 +32,11 @@ exports.inferTitle = function (frontmatter) {
3232
return 'Home'
3333
}
3434
if (frontmatter.data.title) {
35-
return parseHeaders(frontmatter.data.title)
35+
return deeplyParseHeaders(frontmatter.data.title)
3636
}
3737
const match = frontmatter.content.trim().match(/^#+\s+(.*)/)
3838
if (match) {
39-
return parseHeaders(match[1])
39+
return deeplyParseHeaders(match[1])
4040
}
4141
}
4242

@@ -68,11 +68,11 @@ exports.extractHeaders = function (content, include = [], md) {
6868
const res = []
6969
tokens.forEach((t, i) => {
7070
if (t.type === 'heading_open' && include.includes(t.tag)) {
71-
const title = parseHeaders(tokens[i + 1].content)
71+
const title = tokens[i + 1].content
7272
const slug = t.attrs.find(([name]) => name === 'id')[1]
7373
res.push({
7474
level: parseInt(t.tag.slice(1), 10),
75-
title,
75+
title: deeplyParseHeaders(title),
7676
slug: slug || md.slugify(title)
7777
})
7878
}

lib/util/parseHeaders.js

+16-8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const { compose } = require('./shared')
2+
13
const parseEmojis = str => {
24
const emojiData = require('markdown-it-emoji/lib/data/full.json')
35
return String(str).replace(/:(.+?):/g, (placeholder, key) => emojiData[key] || placeholder)
@@ -17,13 +19,19 @@ const removeMarkdownToken = str => String(str)
1719
.replace(/\*(.*)\*/, '$1') // *
1820
.replace(/_(.*)_/, '$1') // _
1921

20-
// put here to avoid circular references
21-
const compose = (...processors) => {
22-
if (processors.length === 0) return input => input
23-
if (processors.length === 1) return processors[0]
24-
return processors.reduce((prev, next) => {
25-
return (...args) => next(prev(...args))
26-
})
22+
exports.removeTailHtml = (str) => {
23+
return String(str).replace(/<.*>\s*$/g, '')
2724
}
2825

29-
module.exports = compose(unescapeHtml, parseEmojis, removeMarkdownToken)
26+
// only remove some md tokens.
27+
exports.parseHeaders = compose(
28+
unescapeHtml,
29+
parseEmojis,
30+
removeMarkdownToken
31+
)
32+
33+
// also clean html in headers.
34+
exports.deeplyParseHeaders = compose(
35+
exports.parseHeaders,
36+
exports.removeTailHtml
37+
)

lib/util/shared.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
exports.compose = (...processors) => {
2+
if (processors.length === 0) return input => input
3+
if (processors.length === 1) return processors[0]
4+
return processors.reduce((prev, next) => {
5+
return (...args) => next(prev(...args))
6+
})
7+
}

0 commit comments

Comments
 (0)