2024-11-30 02:19:32 +01:00
|
|
|
<template>
|
2025-07-10 05:13:42 +02:00
|
|
|
<div class="rounded grid grid-cols-[auto_1fr_auto] items-center gap-3">
|
2025-12-09 22:32:22 +01:00
|
|
|
<HoverCard
|
|
|
|
|
v-model:open="popupOpen"
|
|
|
|
|
@update:open="() => {
|
2025-04-30 18:03:14 +02:00
|
|
|
if (!preferences.popup_avatar_hover) {
|
2024-12-04 12:47:17 +01:00
|
|
|
popupOpen = false;
|
|
|
|
|
}
|
2025-12-09 22:32:22 +01:00
|
|
|
}"
|
|
|
|
|
:open-delay="2000"
|
|
|
|
|
>
|
2024-12-04 12:47:17 +01:00
|
|
|
<HoverCardTrigger :as-child="true">
|
2025-12-09 22:32:22 +01:00
|
|
|
<NuxtLink
|
|
|
|
|
:href="urlAsPath"
|
|
|
|
|
:class="cn('relative size-12', smallLayout && 'size-8')"
|
|
|
|
|
>
|
|
|
|
|
<Avatar
|
|
|
|
|
:class="cn('size-12 border border-card', smallLayout && 'size-8')"
|
|
|
|
|
:src="author.avatar"
|
|
|
|
|
:name="author.display_name"
|
|
|
|
|
/>
|
|
|
|
|
<Avatar
|
|
|
|
|
v-if="cornerAvatar"
|
|
|
|
|
class="size-6 border absolute -bottom-1 -right-1"
|
|
|
|
|
:src="cornerAvatar"
|
|
|
|
|
/>
|
2024-12-04 12:47:17 +01:00
|
|
|
</NuxtLink>
|
|
|
|
|
</HoverCardTrigger>
|
|
|
|
|
<HoverCardContent class="w-96">
|
2025-12-09 22:32:22 +01:00
|
|
|
<SmallCard :account="author"/>
|
2024-12-04 12:47:17 +01:00
|
|
|
</HoverCardContent>
|
|
|
|
|
</HoverCard>
|
2025-12-09 22:32:22 +01:00
|
|
|
<Column :class="smallLayout && 'text-sm'">
|
|
|
|
|
<Text class="font-semibold" v-render-emojis="author.emojis">
|
|
|
|
|
{{
|
2024-12-04 12:47:17 +01:00
|
|
|
author.display_name
|
2025-12-09 22:32:22 +01:00
|
|
|
}}
|
|
|
|
|
</Text>
|
2025-07-10 05:13:42 +02:00
|
|
|
<div class="-mt-1">
|
2025-12-09 22:32:22 +01:00
|
|
|
<Address as="span" :username="username" :domain="instance"/>
|
2024-11-30 02:19:32 +01:00
|
|
|
·
|
2025-12-09 22:32:22 +01:00
|
|
|
<Text
|
|
|
|
|
as="span"
|
|
|
|
|
muted
|
|
|
|
|
class="ml-auto tracking-normal"
|
|
|
|
|
:title="fullTime"
|
|
|
|
|
>
|
|
|
|
|
{{ timeAgo }}
|
|
|
|
|
</Text>
|
2025-07-10 05:13:42 +02:00
|
|
|
</div>
|
2025-12-09 22:32:22 +01:00
|
|
|
</Column>
|
2025-07-10 05:13:42 +02:00
|
|
|
<div v-if="!smallLayout">
|
2025-12-09 22:32:22 +01:00
|
|
|
<NuxtLink
|
|
|
|
|
:href="noteUrlAsPath"
|
|
|
|
|
class="text-xs text-muted-foreground"
|
|
|
|
|
:title="visibilities[visibility].text"
|
|
|
|
|
>
|
|
|
|
|
<component :is="visibilities[visibility].icon" class="size-4"/>
|
2024-12-02 22:29:08 +01:00
|
|
|
</NuxtLink>
|
2024-11-30 02:19:32 +01:00
|
|
|
</div>
|
2024-11-30 18:21:40 +01:00
|
|
|
</div>
|
2024-11-30 02:19:32 +01:00
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
2025-05-26 11:19:15 +02:00
|
|
|
import type { Account, Status } from "@versia/client/schemas";
|
2024-12-02 11:17:25 +01:00
|
|
|
import type {
|
|
|
|
|
UseTimeAgoMessages,
|
|
|
|
|
UseTimeAgoUnitNamesDefault,
|
|
|
|
|
} from "@vueuse/core";
|
2024-11-30 02:19:32 +01:00
|
|
|
import { AtSign, Globe, Lock, LockOpen } from "lucide-vue-next";
|
2025-05-26 11:19:15 +02:00
|
|
|
import type { z } from "zod";
|
2025-06-26 22:39:02 +02:00
|
|
|
import { cn } from "@/lib/utils";
|
2025-07-16 07:48:39 +02:00
|
|
|
import { getLocale } from "~~/paraglide/runtime";
|
2025-07-10 05:13:42 +02:00
|
|
|
import Address from "../profiles/address.vue";
|
2024-12-03 14:07:00 +01:00
|
|
|
import Avatar from "../profiles/avatar.vue";
|
2024-12-04 12:47:17 +01:00
|
|
|
import SmallCard from "../profiles/small-card.vue";
|
2025-12-09 22:32:22 +01:00
|
|
|
import Column from "../typography/layout/col.vue";
|
2025-07-10 05:13:42 +02:00
|
|
|
import Text from "../typography/text.vue";
|
2024-12-04 12:47:17 +01:00
|
|
|
import {
|
|
|
|
|
HoverCard,
|
|
|
|
|
HoverCardContent,
|
|
|
|
|
HoverCardTrigger,
|
|
|
|
|
} from "../ui/hover-card";
|
2024-11-30 02:19:32 +01:00
|
|
|
|
2024-12-04 12:47:17 +01:00
|
|
|
const { createdAt, noteUrl, author, authorUrl } = defineProps<{
|
2024-11-30 16:21:16 +01:00
|
|
|
cornerAvatar?: string;
|
2025-05-26 11:19:15 +02:00
|
|
|
visibility: z.infer<typeof Status.shape.visibility>;
|
2024-12-02 22:29:08 +01:00
|
|
|
noteUrl: string;
|
2024-11-30 02:19:32 +01:00
|
|
|
createdAt: Date;
|
2024-11-30 16:39:02 +01:00
|
|
|
smallLayout?: boolean;
|
2025-05-26 11:19:15 +02:00
|
|
|
author: z.infer<typeof Account>;
|
2024-12-04 12:47:17 +01:00
|
|
|
authorUrl: string;
|
2024-11-30 02:19:32 +01:00
|
|
|
}>();
|
|
|
|
|
|
2024-12-04 12:47:17 +01:00
|
|
|
const [username, instance] = author.acct.split("@");
|
2024-12-02 11:17:25 +01:00
|
|
|
const digitRegex = /\d/;
|
2024-12-04 12:47:17 +01:00
|
|
|
const urlAsPath = new URL(authorUrl).pathname;
|
2024-12-02 22:29:08 +01:00
|
|
|
const noteUrlAsPath = new URL(noteUrl).pathname;
|
2024-12-02 11:17:25 +01:00
|
|
|
const timeAgo = useTimeAgo(createdAt, {
|
|
|
|
|
messages: {
|
|
|
|
|
justNow: "now",
|
|
|
|
|
past: (n) => (n.match(digitRegex) ? `${n}` : n),
|
|
|
|
|
future: (n) => (n.match(digitRegex) ? `in ${n}` : n),
|
|
|
|
|
month: (n) => `${n}mo`,
|
|
|
|
|
year: (n) => `${n}y`,
|
|
|
|
|
day: (n) => `${n}d`,
|
|
|
|
|
week: (n) => `${n}w`,
|
|
|
|
|
hour: (n) => `${n}h`,
|
|
|
|
|
minute: (n) => `${n}m`,
|
|
|
|
|
second: (n) => `${n}s`,
|
|
|
|
|
invalid: "",
|
|
|
|
|
} as UseTimeAgoMessages<UseTimeAgoUnitNamesDefault>,
|
|
|
|
|
});
|
2025-02-14 14:08:21 +01:00
|
|
|
const fullTime = new Intl.DateTimeFormat(getLocale(), {
|
2024-11-30 02:19:32 +01:00
|
|
|
dateStyle: "medium",
|
|
|
|
|
timeStyle: "short",
|
|
|
|
|
}).format(createdAt);
|
2024-12-04 12:47:17 +01:00
|
|
|
const popupOpen = ref(false);
|
2024-11-30 02:19:32 +01:00
|
|
|
|
|
|
|
|
const visibilities = {
|
|
|
|
|
public: {
|
|
|
|
|
icon: Globe,
|
|
|
|
|
text: "This note is public: it can be seen by anyone.",
|
|
|
|
|
},
|
|
|
|
|
unlisted: {
|
|
|
|
|
icon: LockOpen,
|
|
|
|
|
text: "This note is unlisted: it can be seen by anyone with the link.",
|
|
|
|
|
},
|
|
|
|
|
private: {
|
|
|
|
|
icon: Lock,
|
|
|
|
|
text: "This note is private: it can only be seen by followers.",
|
|
|
|
|
},
|
|
|
|
|
direct: {
|
|
|
|
|
icon: AtSign,
|
|
|
|
|
text: "This note is direct: it can only be seen by mentioned users.",
|
|
|
|
|
},
|
|
|
|
|
};
|
2024-12-31 15:55:02 +01:00
|
|
|
</script>
|