feat: support custom emojis from other servers

zio/stable
Anthony Fu 2022-11-23 07:42:20 +08:00
parent f3a0a5af3f
commit 6d66bbbc5d
10 changed files with 40 additions and 16 deletions

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
import type { Account } from 'masto'
defineProps<{
account: Account
}>()
</script>
<template>
<img :src="account.avatar" :alt="account.username" rounded bg-gray:10>
</template>

View File

@ -21,11 +21,11 @@ const createdAt = $computed(() => {
<div flex flex-col gap-2> <div flex flex-col gap-2>
<div p1> <div p1>
<NuxtLink :to="`/@${account.acct}`"> <NuxtLink :to="`/@${account.acct}`">
<img :src="account.avatar" rounded w-20 h-20> <AccountAvatar :account="account" w-20 h-20 />
</NuxtLink> </NuxtLink>
</div> </div>
<NuxtLink flex flex-col :to="`/@${account.acct}`"> <NuxtLink flex flex-col :to="`/@${account.acct}`">
<CommonRichContent font-bold :content="getDisplayName(account)" /> <CommonRichContent font-bold :content="getDisplayName(account)" :emojis="account.emojis" />
<p op50> <p op50>
@{{ account.acct }} @{{ account.acct }}
</p> </p>

View File

@ -11,11 +11,11 @@ const { link = true } = defineProps<{
<div flex gap-2> <div flex gap-2>
<div p1> <div p1>
<NuxtLink :to="link ? `/@${account.acct}` : null"> <NuxtLink :to="link ? `/@${account.acct}` : null">
<img :src="account.avatar" rounded w-10 h-10 bg-gray:10> <AccountAvatar :account="account" w-10 h-10 />
</NuxtLink> </NuxtLink>
</div> </div>
<NuxtLink flex flex-col :to="link ? `/@${account.acct}` : null"> <NuxtLink flex flex-col :to="link ? `/@${account.acct}` : null">
<CommonRichContent font-bold :content="getDisplayName(account)" /> <CommonRichContent font-bold :content="getDisplayName(account)" :emojis="account.emojis" />
<p op35 text-sm> <p op35 text-sm>
@{{ account.acct }} @{{ account.acct }}
</p> </p>

View File

@ -8,7 +8,7 @@ defineProps<{
<template> <template>
<NuxtLink :href="`/@${account.acct}`" flex gap-2 font-bold items-center> <NuxtLink :href="`/@${account.acct}`" flex gap-2 font-bold items-center>
<img :src="account.avatar" class="w-5 h-5 rounded"> <AccountAvatar :account="account" w-5 h-5 />
<CommonRichContent :content="getDisplayName(account)" /> <CommonRichContent :content="getDisplayName(account)" :emojis="account.emojis" />
</NuxtLink> </NuxtLink>
</template> </template>

View File

@ -1,16 +1,24 @@
import type { Emoji } from 'masto'
import type { PropType } from 'vue'
import { emojisArrayToObject } from '~/composables/utils'
export default defineComponent({ export default defineComponent({
props: { props: {
content: { content: {
type: String, type: String,
required: true, required: true,
}, },
emojis: {
type: Array as PropType<Emoji[]>,
},
}, },
setup(props) { setup(props) {
const serverInfos = useServerInfo(currentServer.value) const emojiObject = emojisArrayToObject(props.emojis || [])
return () => h( return () => h(
'div', 'div',
{ class: 'rich-content' }, { class: 'rich-content' },
contentToVNode(props.content, undefined, serverInfos.value?.customEmojis), contentToVNode(props.content, undefined, emojiObject),
) )
}, },
}) })

View File

@ -8,6 +8,6 @@ const { status } = defineProps<{
<template> <template>
<div class="status-body"> <div class="status-body">
<CommonRichContent :content="status.content" /> <CommonRichContent :content="status.content" :emojis="status.emojis" />
</div> </div>
</template> </template>

View File

@ -1,3 +1,4 @@
import { emojisArrayToObject } from './utils'
import type { ServerInfo } from '~/types' import type { ServerInfo } from '~/types'
const ServerInfoTTL = 60 * 60 * 1000 * 12 // 12 hour const ServerInfoTTL = 60 * 60 * 1000 * 12 // 12 hour
@ -19,7 +20,7 @@ async function _fetchServerInfo(server: string) {
Object.assign(serverInfos.value[server], r) Object.assign(serverInfos.value[server], r)
}), }),
masto.customEmojis.fetchAll().then((r) => { masto.customEmojis.fetchAll().then((r) => {
serverInfos.value[server].customEmojis = Object.fromEntries(r.map(i => [i.shortcode, i])) serverInfos.value[server].customEmojis = emojisArrayToObject(r)
}), }),
]) ])
} }

View File

@ -1,3 +1,5 @@
import type { Emoji } from 'masto'
export function getDataUrlFromArr(arr: Uint8ClampedArray, w: number, h: number) { export function getDataUrlFromArr(arr: Uint8ClampedArray, w: number, h: number) {
if (typeof w === 'undefined' || typeof h === 'undefined') if (typeof w === 'undefined' || typeof h === 'undefined')
w = h = Math.sqrt(arr.length / 4) w = h = Math.sqrt(arr.length / 4)
@ -14,3 +16,7 @@ export function getDataUrlFromArr(arr: Uint8ClampedArray, w: number, h: number)
return canvas.toDataURL() return canvas.toDataURL()
} }
export function emojisArrayToObject(emojis: Emoji[]) {
return Object.fromEntries(emojis.map(i => [i.shortcode, i]))
}

View File

@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import AccountAvatar from '~~/components/account/AccountAvatar.vue'
const params = useRoute().params const params = useRoute().params
const id = computed(() => params.post as string) const id = computed(() => params.post as string)
@ -12,8 +14,8 @@ const { data: context } = await useAsyncData(`${id}-context`, () => masto.status
<StatusCard :status="comment" border="t border" pt-4 /> <StatusCard :status="comment" border="t border" pt-4 />
</template> </template>
<StatusDetails :status="status" border="t border" pt-4 /> <StatusDetails :status="status" border="t border" pt-4 />
<div border="t border" p6 flex gap-4> <div v-if="currentUser" border="t border" p6 flex gap-4>
<img :src="currentUser?.account?.avatar" rounded w-10 h-10 bg-gray:10> <AccountAvatar :account="currentUser.account" w-10 h-10 />
<PublishWidget <PublishWidget
w-full w-full
:draft-key="`reply-${id}`" :draft-key="`reply-${id}`"

View File

@ -1,8 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
const props = defineProps<{
modelValue?: boolean
}>()
const params = useRoute().params const params = useRoute().params
const user = $computed(() => params.user as string) const user = $computed(() => params.user as string)