feat: support custom emojis from other servers
This commit is contained in:
parent
f3a0a5af3f
commit
6d66bbbc5d
11
components/account/AccountAvatar.vue
Normal file
11
components/account/AccountAvatar.vue
Normal 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>
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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)
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]))
|
||||||
|
}
|
||||||
|
|
|
@ -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}`"
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue