mirror of
https://github.com/versia-pub/frontend.git
synced 2026-03-13 03:29:16 +01:00
feat: ✨ Render emoji reactions
Some checks failed
Some checks failed
This commit is contained in:
parent
0aef313fc6
commit
b77700b8b8
7 changed files with 101 additions and 9 deletions
|
|
@ -50,6 +50,7 @@
|
|||
:sensitive="noteToUse.sensitive"
|
||||
:content-warning="noteToUse.spoiler_text"
|
||||
/>
|
||||
<Reactions v-if="noteToUse.reactions && noteToUse.reactions.length > 0" :reactions="noteToUse.reactions" :emojis="noteToUse.emojis" :status-id="noteToUse.id" />
|
||||
</CardContent>
|
||||
<CardFooter v-if="!hideActions">
|
||||
<Actions
|
||||
|
|
@ -81,6 +82,7 @@ import { Card, CardContent, CardFooter, CardHeader } from "../ui/card";
|
|||
import Actions from "./actions.vue";
|
||||
import Content from "./content.vue";
|
||||
import Header from "./header.vue";
|
||||
import Reactions from "./reactions/index.vue";
|
||||
import ReblogHeader from "./reblog-header.vue";
|
||||
|
||||
type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
||||
|
|
|
|||
17
components/notes/reactions/index.vue
Normal file
17
components/notes/reactions/index.vue
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<div class="flex flex-row gap-2 flex-wrap">
|
||||
<Reaction v-for="reaction in reactions" :key="reaction.name" :reaction="reaction" :emoji="emojis.find(e => `:${e.shortcode}:` === reaction.name)" :status-id="statusId" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { CustomEmoji, NoteReaction } from "@versia/client/schemas";
|
||||
import type { z } from "zod";
|
||||
import Reaction from "./reaction.vue";
|
||||
|
||||
const { statusId, reactions, emojis } = defineProps<{
|
||||
statusId: string;
|
||||
reactions: z.infer<typeof NoteReaction>[];
|
||||
emojis: z.infer<typeof CustomEmoji>[];
|
||||
}>();
|
||||
</script>
|
||||
73
components/notes/reactions/reaction.vue
Normal file
73
components/notes/reactions/reaction.vue
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
<template>
|
||||
<HoverCard @update:open="(open) => open && accounts === null && refreshReactions()">
|
||||
<HoverCardTrigger as-child>
|
||||
<Button variant="secondary" size="sm" class="gap-2">
|
||||
<img v-if="emoji" :src="emoji.url" :alt="emoji.shortcode"
|
||||
class="h-[1lh] align-middle inline not-prose" />
|
||||
<span v-else>
|
||||
{{ reaction.name }}
|
||||
</span>
|
||||
{{ formatNumber(reaction.count) }}
|
||||
</Button>
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent class="p-3">
|
||||
<Spinner v-if="accounts === null" class="border-0" />
|
||||
<ul v-else class="flex flex-col gap-4">
|
||||
<li
|
||||
v-for="account in accounts">
|
||||
<NuxtLink :to="`/@${account.acct}`" class="flex items-center gap-2">
|
||||
<Avatar class="size-6" :key="account.id" :src="account.avatar"
|
||||
:name="account.display_name || account.username" />
|
||||
<span class="text-sm font-semibold line-clamp-1">
|
||||
{{ account.display_name || account.username }}
|
||||
</span>
|
||||
</NuxtLink>
|
||||
</li>
|
||||
</ul>
|
||||
</HoverCardContent>
|
||||
</HoverCard>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type {
|
||||
Account,
|
||||
CustomEmoji,
|
||||
NoteReaction,
|
||||
} from "@versia/client/schemas";
|
||||
import type { z } from "zod";
|
||||
import Spinner from "~/components/graphics/spinner.vue";
|
||||
import Avatar from "~/components/profiles/avatar.vue";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import {
|
||||
HoverCard,
|
||||
HoverCardContent,
|
||||
HoverCardTrigger,
|
||||
} from "~/components/ui/hover-card";
|
||||
import { getLocale } from "~/paraglide/runtime.js";
|
||||
|
||||
const { reaction, emoji, statusId } = defineProps<{
|
||||
statusId: string;
|
||||
reaction: z.infer<typeof NoteReaction>;
|
||||
emoji?: z.infer<typeof CustomEmoji>;
|
||||
}>();
|
||||
|
||||
const formatNumber = (number: number) =>
|
||||
new Intl.NumberFormat(getLocale(), {
|
||||
notation: "compact",
|
||||
compactDisplay: "short",
|
||||
maximumFractionDigits: 1,
|
||||
}).format(number);
|
||||
|
||||
const accounts = ref<z.infer<typeof Account>[] | null>(null);
|
||||
|
||||
const refreshReactions = async () => {
|
||||
const { data } = await client.value.getStatusReactions(statusId);
|
||||
const accountIds =
|
||||
data.find((r) => r.name === reaction.name)?.account_ids.slice(0, 10) ??
|
||||
[];
|
||||
|
||||
const { data: accountsData } = await client.value.getAccounts(accountIds);
|
||||
|
||||
accounts.value = accountsData;
|
||||
};
|
||||
</script>
|
||||
Loading…
Add table
Add a link
Reference in a new issue