diff --git a/components/status/StatusBody.vue b/components/status/StatusBody.vue index d91b5ad9..eab2637f 100644 --- a/components/status/StatusBody.vue +++ b/components/status/StatusBody.vue @@ -17,6 +17,7 @@ const vnode = $computed(() => { return null const vnode = contentToVNode(status.content, { emojis: emojisObject.value, + mentions: 'mentions' in status ? status.mentions : undefined, markdown: true, }) return vnode diff --git a/composables/content-parse.ts b/composables/content-parse.ts index 683e93d1..dea3d5b2 100644 --- a/composables/content-parse.ts +++ b/composables/content-parse.ts @@ -8,6 +8,7 @@ import { emojiRegEx, getEmojiAttributes } from '../config/emojis' export interface ContentParseOptions { emojis?: Record + mentions?: mastodon.v1.StatusMention[] markdown?: boolean replaceUnicodeEmoji?: boolean astTransforms?: Transform[] @@ -47,6 +48,7 @@ export function parseMastodonHTML( markdown = true, replaceUnicodeEmoji = true, convertMentionLink = false, + mentions, } = options if (markdown) { @@ -74,6 +76,9 @@ export function parseMastodonHTML( if (markdown) transforms.push(transformMarkdown) + if (mentions?.length) + transforms.push(createTransformNamedMentions(mentions)) + if (convertMentionLink) transforms.push(transformMentionLink) @@ -377,3 +382,18 @@ function transformMentionLink(node: Node): string | Node | (string | Node)[] | n } return node } + +function createTransformNamedMentions(mentions: mastodon.v1.StatusMention[]) { + return (node: Node): string | Node | (string | Node)[] | null => { + if (node.name === 'a' && node.attributes.class?.includes('mention')) { + const href = node.attributes.href + const mention = href && mentions.find(m => m.url === href) + if (mention) { + node.attributes.href = `/${currentServer.value}/@${mention.acct}` + node.children = [h('span', { 'data-type': 'mention', 'data-id': mention.acct }, `@${mention.username}`)] + return node + } + } + return node + } +} diff --git a/tests/__snapshots__/content-rich.test.ts.snap b/tests/__snapshots__/content-rich.test.ts.snap index 1dde47cf..c7202ea1 100644 --- a/tests/__snapshots__/content-rich.test.ts.snap +++ b/tests/__snapshots__/content-rich.test.ts.snap @@ -40,6 +40,19 @@ exports[`content-rich > custom emoji 1`] = ` exports[`content-rich > empty 1`] = `""`; +exports[`content-rich > group mention > html 1`] = ` +"

+ +

+" +`; + exports[`content-rich > handles html within code blocks 1`] = ` "

HTML block code:
diff --git a/tests/content-rich.test.ts b/tests/content-rich.test.ts index 700fe4ff..c3df5b0c 100644 --- a/tests/content-rich.test.ts +++ b/tests/content-rich.test.ts @@ -20,6 +20,11 @@ describe('content-rich', () => { expect(formatted).toMatchSnapshot() }) + it('group mention', async () => { + const { formatted } = await render('

@pilipinas

', undefined, [{ id: '', username: 'pilipinas', url: 'https://lemmy.ml/c/pilipinas', acct: 'pilipinas@lemmy.ml' }]) + expect(formatted).toMatchSnapshot('html') + }) + it('inline code with link', async () => { const { formatted } = await render('

Inline code with link: `api.iconify.design/noto.css?ic`

') expect(formatted).toMatchSnapshot() @@ -64,8 +69,8 @@ describe('content-rich', () => { }) }) -async function render(content: string, emojis?: Record) { - const vnode = contentToVNode(content, { emojis }) +async function render(content: string, emojis?: Record, mentions?: mastodon.v1.StatusMention[]) { + const vnode = contentToVNode(content, { emojis, mentions }) const html = (await renderToString(vnode)) .replace(//g, '') let formatted = ''