diff --git a/__tests__/e2e/home.test.ts b/__tests__/e2e/home.test.ts index 9b02c1a239c3..76868361f671 100644 --- a/__tests__/e2e/home.test.ts +++ b/__tests__/e2e/home.test.ts @@ -14,12 +14,12 @@ describe('render correct content', async () => { pLocator.allTextContents() ]) - expect(h1Contents).toEqual(['Lorem Ipsum #']) - expect(h2Contents).toEqual([ - 'What is Lorem Ipsum? #', - 'Where does it come from? #', - 'Why do we use it? #', - 'Where can I get some? #' + expect(h1Contents).toEqual(['Lorem Ipsum \u200b']) + expect(h2Contents.map((s) => s.trim())).toEqual([ + 'What is Lorem Ipsum? \u200b', + 'Where does it come from? \u200b', + 'Why do we use it? \u200b', + 'Where can I get some? \u200b' ]) expect(pContents).toMatchSnapshot() }) diff --git a/src/client/theme-default/styles/components/vp-doc.css b/src/client/theme-default/styles/components/vp-doc.css index 11d8bb00fbe2..5c8349b7010b 100644 --- a/src/client/theme-default/styles/components/vp-doc.css +++ b/src/client/theme-default/styles/components/vp-doc.css @@ -45,6 +45,10 @@ transition: color 0.25s, opacity 0.25s; } +.vp-doc .header-anchor:before { + content: var(--vp-header-anchor-symbol); +} + .vp-doc h1:hover .header-anchor, .vp-doc h1 .header-anchor:focus, .vp-doc h2:hover .header-anchor, diff --git a/src/client/theme-default/styles/vars.css b/src/client/theme-default/styles/vars.css index 84ea1af652a6..29a1c527c22d 100644 --- a/src/client/theme-default/styles/vars.css +++ b/src/client/theme-default/styles/vars.css @@ -193,6 +193,14 @@ --vp-layout-max-width: 1440px; } +/** + * Component: Header Anchor + * -------------------------------------------------------------------------- */ + +:root { + --vp-header-anchor-symbol: '#'; +} + /** * Component: Code * -------------------------------------------------------------------------- */ diff --git a/src/node/markdown/markdown.ts b/src/node/markdown/markdown.ts index 54b8edc1764e..375841401cba 100644 --- a/src/node/markdown/markdown.ts +++ b/src/node/markdown/markdown.ts @@ -99,7 +99,22 @@ export const createMarkdownRenderer = async ( // mdit-vue plugins md.use(anchorPlugin, { slugify, - permalink: anchorPlugin.permalink.ariaHidden({}), + permalink: anchorPlugin.permalink.linkInsideHeader({ + symbol: '​', + renderAttrs: (slug, state) => { + // Find `heading_open` with the id identical to slug + const idx = state.tokens.findIndex((token) => { + const attrs = token.attrs + const id = attrs?.find((attr) => attr[0] === 'id') + return id && slug === id[1] + }) + // Get the actual heading content + const title = state.tokens[idx + 1].content + return { + 'aria-label': `Permalink to "${title}"` + } + } + }), ...options.anchor } as anchorPlugin.AnchorOptions).use(frontmatterPlugin, { ...options.frontmatter