Skip to content

Commit

Permalink
feat: add LTR/RTL in hashtags and mentions support (elk-zone#2541)
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel Roe <daniel@roe.dev>
  • Loading branch information
userquin and danielroe authored Jan 4, 2024
1 parent b016320 commit 3adf92e
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 106 deletions.
6 changes: 4 additions & 2 deletions components/tag/TagCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@ function go(evt: MouseEvent | KeyboardEvent) {
<div>
<h4 flex items-center text-size-base leading-normal font-medium line-clamp-1 break-all ws-pre-wrap>
<TagActionButton :tag="tag" />
<span>#</span>
<span hover:underline>{{ tag.name }}</span>
<bdi>
<span>#</span>
<span hover:underline>{{ tag.name }}</span>
</bdi>
</h4>
<CommonTrending v-if="tag.history" :history="tag.history" text-sm text-secondary line-clamp-1 ws-pre-wrap break-all />
</div>
Expand Down
4 changes: 4 additions & 0 deletions composables/content-parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ const sanitizer = sanitize({
/**
* Parse raw HTML form Mastodon server to AST,
* with interop of custom emojis and inline Markdown syntax
* @param html The content to parse
* @param options The parsing options
*/
export function parseMastodonHTML(
html: string,
Expand Down Expand Up @@ -140,6 +142,8 @@ export function parseMastodonHTML(

/**
* Converts raw HTML form Mastodon server to HTML for Tiptap editor
* @param html The content to parse
* @param customEmojis The custom emojis to use
*/
export function convertMastodonHTML(html: string, customEmojis: Record<string, mastodon.v1.CustomEmoji> = {}) {
const tree = parseMastodonHTML(html, {
Expand Down
23 changes: 21 additions & 2 deletions composables/content-render.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TEXT_NODE } from 'ultrahtml'
import type { Node } from 'ultrahtml'
import { ELEMENT_NODE, TEXT_NODE } from 'ultrahtml'
import type { ElementNode, Node } from 'ultrahtml'
import { Fragment, h, isVNode } from 'vue'
import type { VNode } from 'vue'
import { RouterLink } from 'vue-router'
Expand Down Expand Up @@ -98,6 +98,23 @@ function treeToVNode(
return null
}

function addBdiNode(node: Node) {
if (node.children.length === 1 && node.children[0].type === ELEMENT_NODE && node.children[0].name === 'bdi')
return

const children = node.children.splice(0, node.children.length)
const bdi = {
name: 'bdi',
parent: node,
loc: node.loc,
type: ELEMENT_NODE,
attributes: {},
children,
} satisfies ElementNode
children.forEach((n: Node) => n.parent = bdi)
node.children.push(bdi)
}

function handleMention(el: Node) {
// Redirect mentions to the user page
if (el.name === 'a' && el.attributes.class?.includes('mention')) {
Expand All @@ -108,11 +125,13 @@ function handleMention(el: Node) {
const [, server, username] = matchUser
const handle = `${username}@${server.replace(/(.+\.)(.+\..+)/, '$2')}`
el.attributes.href = `/${server}/@${username}`
addBdiNode(el)
return h(AccountHoverWrapper, { handle, class: 'inline-block' }, () => nodeToVNode(el))
}
const matchTag = href.match(TagLinkRE)
if (matchTag) {
const [, , name] = matchTag
addBdiNode(el)
el.attributes.href = `/${currentServer.value}/tags/${name}`
}
}
Expand Down
2 changes: 1 addition & 1 deletion pages/[[server]]/tags/[tag].vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ onReactivated(() => {
<template>
<MainContent back>
<template #title>
<span text-lg font-bold>#{{ tagName }}</span>
<bdi text-lg font-bold>#{{ tagName }}</bdi>
</template>

<template #actions>
Expand Down
155 changes: 149 additions & 6 deletions tests/nuxt/__snapshots__/content-rich.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ exports[`content-rich > code frame 2 1`] = `
class="u-url mention"
rel="nofollow noopener noreferrer"
to="/webtoo.ls/@antfu"
></a
></span>
><bdi>@<span>antfu</span></bdi></a
></span
>
Testing<br />
<pre class="code-block">const a = hello</pre>
</p>
Expand All @@ -56,6 +57,62 @@ exports[`content-rich > code frame empty 1`] = `"<p><pre class="code-block"></pr
exports[`content-rich > code frame no lang 1`] = `"<p><pre class="code-block">hello world</pre><br>no lang</p>"`;
exports[`content-rich > collapse mentions 1`] = `
"<p>
<span class="h-card"
><a
class="u-url mention"
rel="nofollow noopener noreferrer"
to="/m.webtoo.ls/@elk"
><bdi>@<span>elk</span></bdi></a
></span
>
<span class="h-card"
><a
class="u-url mention"
rel="nofollow noopener noreferrer"
to="/m.webtoo.ls/@elk"
><bdi>@<span>elk</span></bdi></a
></span
>
content
<span class="h-card"
><a
class="u-url mention"
rel="nofollow noopener noreferrer"
to="/m.webtoo.ls/@antfu"
><bdi>@<span>antfu</span></bdi></a
></span
>
<span class="h-card"
><a
class="u-url mention"
rel="nofollow noopener noreferrer"
to="/mastodon.roe.dev/@daniel"
><bdi>@<span>daniel</span></bdi></a
></span
>
<span class="h-card"
><a
class="u-url mention"
rel="nofollow noopener noreferrer"
to="/m.webtoo.ls/@sxzz"
><bdi>@<span>sxzz</span></bdi></a
></span
>
<span class="h-card"
><a
class="u-url mention"
rel="nofollow noopener noreferrer"
to="/m.webtoo.ls/@patak"
><bdi>@<span>patak</span></bdi></a
></span
>
content
</p>
"
`;
exports[`content-rich > custom emoji 1`] = `
"Daniel Roe
<picture class="custom-emoji" alt=":nuxt:" data-emoji-id="nuxt" title="nuxt"
Expand All @@ -81,8 +138,13 @@ exports[`content-rich > group mention > html 1`] = `
class="u-url mention"
rel="nofollow noopener noreferrer"
to="/m.webtoo.ls/@pilipinas@lemmy.ml"
></a
></span>
><bdi
><span data-type="mention" data-id="pilipinas@lemmy.ml"
>@pilipinas</span
></bdi
></a
></span
>
</p>
"
`;
Expand Down Expand Up @@ -115,6 +177,39 @@ exports[`content-rich > handles html within code blocks 1`] = `
"
`;
exports[`content-rich > hashtag adds bdi 1`] = `
"<p>
Testing bdi is added
<a
class="mention hashtag"
rel="nofollow noopener noreferrer"
to="/m.webtoo.ls/tags/turkey"
><bdi>#<span>turkey</span></bdi></a
>
</p>
<p></p>
"
`;
exports[`content-rich > hashtag doesn't add 2 bdi 1`] = `
"<p>
Testing bdi not added
<a
class="mention hashtag"
rel="nofollow noopener noreferrer"
to="/m.webtoo.ls/tags/turkey"
><bdi></bdi
></a>
</p>
<p></p>
"
`;
exports[`content-rich > hides collapsed mentions 1`] = `
"<p>content</p>
"
`;
exports[`content-rich > inline code with link 1`] = `
"<p>
Inline code with link:
Expand All @@ -139,8 +234,9 @@ exports[`content-rich > link + mention 1`] = `
class="u-url mention"
rel="nofollow noopener noreferrer"
to="/webtoo.ls/@vitest"
></a
></span>
><bdi>@<span>vitest</span></bdi></a
></span
>
(migrated from chai+mocha)
<a
href="https://github.com/ayoayco/astro-reactive-library/pull/203"
Expand All @@ -159,6 +255,53 @@ exports[`content-rich > plain text 1`] = `
"
`;
exports[`content-rich > shows some collapsed mentions grouped 1`] = `
"<p>
<mention-group
><span class="h-card"
><a
class="u-url mention"
rel="nofollow noopener noreferrer"
to="/m.webtoo.ls/@antfu"
><bdi>@<span>antfu</span></bdi></a
></span
>
<span class="h-card"
><a
class="u-url mention"
rel="nofollow noopener noreferrer"
to="/m.webtoo.ls/@patak"
><bdi>@<span>patak</span></bdi></a
></span
>
<span class="h-card"
><a
class="u-url mention"
rel="nofollow noopener noreferrer"
to="/m.webtoo.ls/@sxzz"
><bdi>@<span>sxzz</span></bdi></a
></span
></mention-group
>content
</p>
"
`;
exports[`content-rich > shows some collapsed mentions inline 1`] = `
"<p>
<span class="h-card"
><a
class="u-url mention"
rel="nofollow noopener noreferrer"
to="/m.webtoo.ls/@antfu"
><bdi>@<span>antfu</span></bdi></a
></span
>
content
</p>
"
`;
exports[`editor > transform mentions 1`] = `
"
@elk Hello"
Expand Down
Loading

0 comments on commit 3adf92e

Please sign in to comment.