kopia lustrzana https://github.com/cloudflare/wildebeest
Merge pull request #287 from cloudflare/custom-emojis-frontend
show custom emojis in display namespull/288/head
commit
c353bca4ff
|
@ -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>
|
||||
boosted
|
||||
</p>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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}</>
|
||||
})}
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -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'
|
||||
)
|
||||
})
|
|
@ -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++
|
||||
|
|
Ładowanie…
Reference in New Issue