show custom emojis in display names

pull/287/head
Dario Piotrowicz 2023-02-15 12:47:55 +00:00
rodzic e89ff9cd59
commit 11a2c278b2
7 zmienionych plików z 90 dodań i 6 usunięć

Wyświetl plik

@ -6,6 +6,7 @@ import type { Account, MastodonStatus } from '~/types'
import styles from '../../utils/innerHtmlContent.scss?inline'
import { MediaGallery } from '../MediaGallery.tsx'
import { useAccountUrl } from '~/utils/useAccountUrl'
import { getDisplayNameElement } from '~/utils/getDisplayNameElement'
type Props = {
status: MastodonStatus
@ -33,7 +34,7 @@ export default component$((props: Props) => {
<div class="flex-col ml-3">
<div>
<Link class="no-underline" href={accountUrl}>
{status.account.display_name}
{getDisplayNameElement(status.account)}
</Link>
</div>
<div class="text-wildebeest-500">@{status.account.username}</div>
@ -75,7 +76,7 @@ export const RebloggerLink = component$(({ account }: { account: Account | null
<p>
<i class="fa fa-retweet mr-3 w-4 inline-block" />
<a class="no-underline" href={accountUrl}>
{account.display_name}
{getDisplayNameElement(account)}
</a>
&nbsp;boosted
</p>

Wyświetl plik

@ -15,6 +15,7 @@ import styles from '../../../../utils/innerHtmlContent.scss?inline'
import { getTextContent } from 'wildebeest/backend/src/activitypub/objects'
import { getDocumentHead } from '~/utils/getDocumentHead'
import { useAccountUrl } from '~/utils/useAccountUrl'
import { getDisplayNameElement } from '~/utils/getDisplayNameElement'
export const statusLoader = loader$<
{ DATABASE: D1Database },
@ -81,7 +82,7 @@ export const AccountCard = component$<{ status: MastodonStatus }>(({ status }) =
<div class="flex flex-col">
<div class="p-1">
<Link href={accountUrl} class="no-underline">
{status.account.display_name}
{getDisplayNameElement(status.account)}
</Link>
</div>
<div class="p-1 text-wildebeest-400">@{status.account.acct}</div>

Wyświetl plik

@ -9,10 +9,11 @@ import { getAccount } from 'wildebeest/backend/src/accounts/getAccount'
import { getNotFoundHtml } from '~/utils/getNotFoundHtml/getNotFoundHtml'
import { getErrorHtml } from '~/utils/getErrorHtml/getErrorHtml'
import { getDocumentHead } from '~/utils/getDocumentHead'
import type { MastodonStatus } from '~/types'
import type { Account, MastodonStatus } from '~/types'
import { StatusesPanel } from '~/components/StatusesPanel/StatusesPanel'
import { parseHandle } from 'wildebeest/backend/src/utils/parse'
import { getLocalStatuses } from 'wildebeest/functions/api/v1/accounts/[id]/statuses'
import { getDisplayNameElement } from '~/utils/getDisplayNameElement'
export const accountLoader = loader$<
{ DATABASE: D1Database },
@ -93,7 +94,7 @@ export default component$(() => {
/>
</div>
<div class="px-5">
<h2 class="font-bold">{accountDetails.account.display_name}</h2>
<h2 class="font-bold">{getDisplayNameElement(accountDetails.account as Account)}</h2>
<span class="block my-1 text-wildebeest-400">{accountDetails.accountHandle}</span>
<div class="inner-html-content my-5" dangerouslySetInnerHTML={accountDetails.account.note} />
<dl class="mb-6 flex flex-col bg-wildebeest-800 border border-wildebeest-600 rounded-md">

Wyświetl plik

@ -65,3 +65,14 @@ button {
.pointer {
cursor: pointer;
}
.custom-emoji {
display: inline-block;
font-size: inherit;
vertical-align: middle;
-o-object-fit: contain;
object-fit: contain;
margin: -.2ex 0.15em .2ex;
width: 1rem;
height: 1rem;
}

Wyświetl plik

@ -0,0 +1,21 @@
import { type JSXNode } from '@builder.io/qwik'
import { type Account } from '~/types'
export function getDisplayNameElement(account: Account): JSXNode {
return (
<>
{account.display_name.split(/(:[^\s:]+:)/g).map((str) => {
const customEmojiMatch = str.match(/^:([^\s:]+):$/)
if (customEmojiMatch) {
const shortCode = customEmojiMatch[1]
const customEmojiInfo = account.emojis.find((emoji) => emoji.shortcode === shortCode)
if (customEmojiInfo) {
// eslint-disable-next-line qwik/single-jsx-root
return <img class="custom-emoji" src={customEmojiInfo.url} alt={`:${shortCode}:`}></img>
}
}
return <>{str}</>
})}
</>
)
}

Wyświetl plik

@ -0,0 +1,49 @@
import { test, expect } from '@playwright/test'
test('View of custom emojis in an toots author display name', async ({ page, browserName }) => {
// this page.route is a hack to mock the custom emojis since they haven't
// yet been implemented in the backend (this should be not needed and removed
// when those are implemented)
test.skip(
browserName !== 'chromium',
"Only chromium seem to test this well, I suspect it's because of the page.route"
)
await page.route('http://127.0.0.1:8788/@george/*/q-data.json', async (route) => {
const response = await route.fetch()
let body = await response.text()
body = body.replace(
/"emojis":\[\]/g,
`"emojis": ${JSON.stringify([
{
shortcode: 'verified',
url: 'https://files.mastodon.social/cache/custom_emojis/images/000/452/462/original/947cae7ac4dfdfa0.png',
static_url:
'https://files.mastodon.social/cache/custom_emojis/images/000/452/462/static/947cae7ac4dfdfa0.png',
visible_in_picker: true,
},
])}`
)
await route.fulfill({
response,
body,
})
})
await page.goto('http://127.0.0.1:8788/explore')
await page
.locator('article')
.filter({ hasText: 'George' })
.filter({
hasText: 'We did it!',
})
.locator('i.fa-globe + span')
.click()
const customEmojiLocator = page.getByRole('link', { name: 'George :verified: 👍', exact: true }).getByRole('img')
await expect(customEmojiLocator).toBeVisible()
await expect(customEmojiLocator).toHaveAttribute(
'src',
'https://files.mastodon.social/cache/custom_emojis/images/000/452/462/original/947cae7ac4dfdfa0.png'
)
})

Wyświetl plik

@ -84,7 +84,7 @@ export function getMockStatusFn(): () => MastodonStatus {
const paddedNum = `${numOfGeneratedMockStatuses}`.padStart(3, '0')
const status = {
content: `Mock Fetched Status #${paddedNum}`,
account: {} as Account,
account: { display_name: 'test', emojis: [] } as unknown as Account,
media_attachments: [],
} as unknown as MastodonStatus
numOfGeneratedMockStatuses++