refactor and fix all references to emojis

This commit is contained in:
Moon.eth
2026-07-30 17:59:15 +09:00
parent b814d79f19
commit 49c9c2ba57
28 changed files with 422 additions and 77 deletions
+7 -3
View File
@@ -6,14 +6,16 @@
* when it's revealed, and the reveal is per-attachment because a single post
* can mix flagged and unflagged media.
*/
import type { MediaAttachment } from '$lib/api/types'
import type { CustomEmoji, MediaAttachment } from '$lib/api/types'
import EmojiText from '../common/EmojiText.svelte'
interface Props {
attachments: MediaAttachment[]
emojis?: CustomEmoji[]
sensitive?: boolean
}
let { attachments, sensitive = false }: Props = $props()
let { attachments, emojis, sensitive = false }: Props = $props()
let revealed = $state<Record<string, boolean>>({})
@@ -81,7 +83,9 @@
{/if}
{#if media.description}
<figcaption class="attachment-caption">{media.description}</figcaption>
<figcaption class="attachment-caption">
<EmojiText text={media.description} {emojis} />
</figcaption>
{/if}
</figure>
+11 -4
View File
@@ -17,6 +17,7 @@
import { isoDate, longDate, stampDate } from '$lib/util/time'
import { extractYouTubeVideoIds } from '$lib/util/youtube'
import Avatar from '../common/Avatar.svelte'
import EmojiText from '../common/EmojiText.svelte'
import MfmContent from '../common/MfmContent.svelte'
import Attachments from './Attachments.svelte'
import EmojiReactions from './EmojiReactions.svelte'
@@ -145,7 +146,10 @@
>
{#if booster}
<p class="blog-entry-attribution">
<a href={profilePath(booster)}>{displayNameOf(booster)}</a> reposted this
<a href={profilePath(booster)}>
<EmojiText text={displayNameOf(booster)} emojis={booster.emojis} />
</a>
reposted this
</p>
{/if}
@@ -181,7 +185,9 @@
<div class="blog-entry-body">
{#if entry.spoiler_text}
<details class="content-warning">
<summary class="content-warning-summary">{entry.spoiler_text}</summary>
<summary class="content-warning-summary">
<EmojiText text={entry.spoiler_text} emojis={entry.emojis} />
</summary>
<MfmContent
html={entry.content}
emojis={entry.emojis}
@@ -190,7 +196,7 @@
lang={entry.language}
/>
{#if entry.media_attachments.length > 0}
<Attachments attachments={entry.media_attachments} sensitive={entry.sensitive} />
<Attachments attachments={entry.media_attachments} emojis={entry.emojis} sensitive={entry.sensitive} />
{/if}
<YouTubeEmbeds videoIds={youtubeVideoIds} sensitive={entry.sensitive} />
</details>
@@ -203,7 +209,7 @@
lang={entry.language}
/>
{#if entry.media_attachments.length > 0}
<Attachments attachments={entry.media_attachments} sensitive={entry.sensitive} />
<Attachments attachments={entry.media_attachments} emojis={entry.emojis} sensitive={entry.sensitive} />
{/if}
<YouTubeEmbeds videoIds={youtubeVideoIds} sensitive={entry.sensitive} />
{/if}
@@ -211,6 +217,7 @@
{#if entry.poll}
<PollView
poll={entry.poll}
emojis={entry.poll.emojis?.length ? entry.poll.emojis : entry.emojis}
authorId={entry.account.id}
onupdate={(poll) => onupdate?.(applyLocal(status, { poll }))}
/>
+5 -3
View File
@@ -1,6 +1,7 @@
<script lang="ts">
import type { EmojiReaction, Status } from '$lib/api/types'
import { useAppServices } from '$lib/app-services'
import { safeCustomEmojiUrl } from '$lib/util/html'
interface Props {
status: Status
@@ -94,11 +95,12 @@
{#if reactions.length > 0}
<div class="emoji-reaction-bar" aria-label="Emoji reactions">
{#each reactions as reaction (reaction.url ?? reaction.name)}
{@const imageUrl = reaction.url ? safeCustomEmojiUrl(reaction.url) : null}
<button
type="button"
class="emoji-reaction"
class:emoji-reaction--mine={reaction.me}
data-custom={reaction.url ? 'true' : 'false'}
data-custom={imageUrl ? 'true' : 'false'}
aria-label={accessibleLabel(reaction)}
aria-pressed={reaction.me ? 'true' : 'false'}
title={session.signedIn
@@ -107,10 +109,10 @@
disabled={!session.signedIn || busyEmoji !== null}
onclick={() => void toggle(reaction)}
>
{#if reaction.url}
{#if imageUrl}
<img
class="emoji-reaction-image"
src={reaction.url}
src={imageUrl}
alt={customLabel(reaction)}
loading="lazy"
decoding="async"
+6 -4
View File
@@ -1,17 +1,19 @@
<script lang="ts">
/** Mastodon/Pleroma poll choices, voting and results. */
import { untrack } from 'svelte'
import type { Poll } from '$lib/api/types'
import type { CustomEmoji, Poll } from '$lib/api/types'
import { useAppServices } from '$lib/app-services'
import { formatCount } from '$lib/util/profile'
import EmojiText from '../common/EmojiText.svelte'
interface Props {
poll: Poll
emojis?: CustomEmoji[]
authorId?: string
onupdate?: (poll: Poll) => void
}
let { poll, authorId, onupdate }: Props = $props()
let { poll, emojis = poll.emojis ?? [], authorId, onupdate }: Props = $props()
const { endpoints, session } = useAppServices()
function pollSignature(value: Poll): string {
@@ -113,7 +115,7 @@
{#if currentPoll.own_votes?.includes(index)}
<span class="poll-own-vote" aria-label="Your vote"></span>
{/if}
{option.title}
<EmojiText text={option.title} {emojis} />
</span>
<span class="poll-option-share">
{option.votes_count === null ? '—' : `${share(option.votes_count)}%`}
@@ -137,7 +139,7 @@
{:else}
<input type="radio" name={`poll-${currentPoll.id}`} value={index} bind:group={singleChoice} />
{/if}
<span>{option.title}</span>
<EmojiText text={option.title} {emojis} />
</label>
{/each}
</fieldset>
+29
View File
@@ -91,4 +91,33 @@ describe('PollView', () => {
expect(view.getByRole('link', { name: 'Sign in to vote' })).toHaveAttribute('href', '#/login')
expect(view.queryByRole('button', { name: 'Vote' })).not.toBeInTheDocument()
})
it('renders custom emoji in poll choices', () => {
const view = render(PollView, {
props: {
poll: poll({
options: [
{ title: 'Choose :blobcat:', votes_count: null },
{ title: 'No thanks', votes_count: null },
],
emojis: [
{
shortcode: 'blobcat',
url: 'https://cdn.example/blobcat.png',
static_url: 'https://cdn.example/blobcat.png',
visible_in_picker: true,
},
],
}),
authorId: 'someone-else',
},
context: new Map([[APP_SERVICES, testServices()]]),
})
expect(view.getByAltText(':blobcat:')).toHaveAttribute(
'src',
'https://cdn.example/blobcat.png',
)
expect(view.getByRole('radio', { name: 'Choose :blobcat:' })).toBeDisabled()
})
})