mirror of
https://github.com/versia-pub/frontend.git
synced 2026-03-13 03:29:16 +01:00
style: 🎨 Format code with Biome
This commit is contained in:
parent
7ff9d2302a
commit
3627ac0ef8
296 changed files with 3257 additions and 2808 deletions
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<Button variant="ghost" class="max-w-14 w-full" size="sm">
|
||||
<component :is="icon" class="size-4" />
|
||||
<slot />
|
||||
<component :is="icon" class="size-4"/>
|
||||
<slot/>
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,58 @@
|
|||
<template>
|
||||
<div class="flex flex-row w-full max-w-sm items-stretch justify-between">
|
||||
<ActionButton :icon="Reply" @click="emit('reply')" :title="m.drab_tense_turtle_comfort()" :disabled="!authStore.isSignedIn">
|
||||
<ActionButton
|
||||
:icon="Reply"
|
||||
@click="emit('reply')"
|
||||
:title="m.drab_tense_turtle_comfort()"
|
||||
:disabled="!authStore.isSignedIn"
|
||||
>
|
||||
{{ numberFormat(replyCount) }}
|
||||
</ActionButton>
|
||||
<ActionButton :icon="Heart" @click="liked ? unlike() : like()" :title="liked ? m.vexed_fluffy_clownfish_dance() : m.royal_close_samuel_scold()" :disabled="!authStore.isSignedIn" :class="liked && '*:fill-red-600 *:text-red-600'">
|
||||
<ActionButton
|
||||
:icon="Heart"
|
||||
@click="liked ? unlike() : like()"
|
||||
:title="liked ? m.vexed_fluffy_clownfish_dance() : m.royal_close_samuel_scold()"
|
||||
:disabled="!authStore.isSignedIn"
|
||||
:class="liked && '*:fill-red-600 *:text-red-600'"
|
||||
>
|
||||
{{ numberFormat(likeCount) }}
|
||||
</ActionButton>
|
||||
<ActionButton :icon="Repeat" @click="reblogged ? unreblog() : reblog()" :title="reblogged ? m.lime_neat_ox_stab() : m.aware_helpful_marlin_drop()" :disabled="!authStore.isSignedIn" :class="reblogged && '*:text-green-600'">
|
||||
<ActionButton
|
||||
:icon="Repeat"
|
||||
@click="reblogged ? unreblog() : reblog()"
|
||||
:title="reblogged ? m.lime_neat_ox_stab() : m.aware_helpful_marlin_drop()"
|
||||
:disabled="!authStore.isSignedIn"
|
||||
:class="reblogged && '*:text-green-600'"
|
||||
>
|
||||
{{ numberFormat(reblogCount) }}
|
||||
</ActionButton>
|
||||
<ActionButton :icon="Quote" @click="emit('quote')" :title="m.true_shy_jackal_drip()" :disabled="!authStore.isSignedIn" />
|
||||
<ActionButton
|
||||
:icon="Quote"
|
||||
@click="emit('quote')"
|
||||
:title="m.true_shy_jackal_drip()"
|
||||
:disabled="!authStore.isSignedIn"
|
||||
/>
|
||||
<Picker @pick="react">
|
||||
<ActionButton :icon="Smile" :title="m.bald_cool_kangaroo_jump()" :disabled="!authStore.isSignedIn" />
|
||||
<ActionButton
|
||||
:icon="Smile"
|
||||
:title="m.bald_cool_kangaroo_jump()"
|
||||
:disabled="!authStore.isSignedIn"
|
||||
/>
|
||||
</Picker>
|
||||
<Menu :api-note-string="apiNoteString" :url="url" :remote-url="remoteUrl" :is-remote="isRemote" :author-id="authorId" @edit="emit('edit')" :note-id="noteId" @delete="emit('delete')">
|
||||
<ActionButton :icon="Ellipsis" :title="m.busy_merry_cowfish_absorb()" />
|
||||
<Menu
|
||||
:api-note-string="apiNoteString"
|
||||
:url="url"
|
||||
:remote-url="remoteUrl"
|
||||
:is-remote="isRemote"
|
||||
:author-id="authorId"
|
||||
@edit="emit('edit')"
|
||||
:note-id="noteId"
|
||||
@delete="emit('delete')"
|
||||
>
|
||||
<ActionButton
|
||||
:icon="Ellipsis"
|
||||
:title="m.busy_merry_cowfish_absorb()"
|
||||
/>
|
||||
</Menu>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,17 @@
|
|||
<template>
|
||||
<ImageAttachment v-if="attachment.type === 'image'" :attachment="attachment" />
|
||||
<VideoAttachment v-else-if="attachment.type === 'video' || attachment.type === 'gifv'" :attachment="attachment" />
|
||||
<AudioAttachment v-else-if="attachment.type === 'audio'" :attachment="attachment" />
|
||||
<FileAttachment v-else :attachment="attachment" />
|
||||
<ImageAttachment
|
||||
v-if="attachment.type === 'image'"
|
||||
:attachment="attachment"
|
||||
/>
|
||||
<VideoAttachment
|
||||
v-else-if="attachment.type === 'video' || attachment.type === 'gifv'"
|
||||
:attachment="attachment"
|
||||
/>
|
||||
<AudioAttachment
|
||||
v-else-if="attachment.type === 'audio'"
|
||||
:attachment="attachment"
|
||||
/>
|
||||
<FileAttachment v-else :attachment="attachment"/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
<template>
|
||||
<!-- [&:has(>:last-child:nth-child(1))] means "when this element has 1 child" -->
|
||||
<div class="grid gap-4 grid-cols-2 *:max-h-56 [&:has(>:last-child:nth-child(1))]:grid-cols-1 sm:[&:has(>:last-child:nth-child(1))>*]:max-h-72">
|
||||
<Attachment v-for="attachment in attachments" :key="attachment.id" :attachment="attachment" />
|
||||
<div
|
||||
class="grid gap-4 grid-cols-2 *:max-h-56 [&:has(>:last-child:nth-child(1))]:grid-cols-1 sm:[&:has(>:last-child:nth-child(1))>*]:max-h-72"
|
||||
>
|
||||
<Attachment
|
||||
v-for="attachment in attachments"
|
||||
:key="attachment.id"
|
||||
:attachment="attachment"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,22 @@
|
|||
<template>
|
||||
<Dialog>
|
||||
<Card class="w-full h-full overflow-hidden relative p-0 *:first:w-full *:first:h-full *:first:object-contain *:first:bg-muted/20">
|
||||
<Card
|
||||
class="w-full h-full overflow-hidden relative p-0 *:first:w-full *:first:h-full *:first:object-contain *:first:bg-muted/20"
|
||||
>
|
||||
<DialogTrigger v-if="lightbox" :as-child="true">
|
||||
<slot />
|
||||
<slot/>
|
||||
</DialogTrigger>
|
||||
<slot v-else />
|
||||
<slot v-else/>
|
||||
<!-- Alt text viewer -->
|
||||
<Popover v-if="attachment.description">
|
||||
<div class="absolute top-0 right-0 p-2">
|
||||
<PopoverTrigger :as-child="true">
|
||||
<Button variant="outline" size="icon" title="View alt text">
|
||||
<Captions />
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
title="View alt text"
|
||||
>
|
||||
<Captions/>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
</div>
|
||||
|
|
@ -19,26 +25,42 @@
|
|||
</PopoverContent>
|
||||
</Popover>
|
||||
</Card>
|
||||
<DialogContent :hide-close="true"
|
||||
class="duration-200 bg-transparent border-none overflow-hidden !animate-none gap-6 w-screen h-screen !max-w-none">
|
||||
<DialogContent
|
||||
:hide-close="true"
|
||||
class="duration-200 bg-transparent border-none overflow-hidden !animate-none gap-6 w-screen h-screen !max-w-none"
|
||||
>
|
||||
<div class="grid grid-rows-[auto_1fr_auto]">
|
||||
<div class="flex flex-row gap-2 w-full">
|
||||
<DialogTitle class="sr-only">{{ attachment.type }}</DialogTitle>
|
||||
<Button as="a" :href="attachment?.url" target="_blank" :download="true" variant="outline" size="icon"
|
||||
class="ml-auto">
|
||||
<Download />
|
||||
<DialogTitle class="sr-only">
|
||||
{{ attachment.type }}
|
||||
</DialogTitle>
|
||||
<Button
|
||||
as="a"
|
||||
:href="attachment?.url"
|
||||
target="_blank"
|
||||
:download="true"
|
||||
variant="outline"
|
||||
size="icon"
|
||||
class="ml-auto"
|
||||
>
|
||||
<Download/>
|
||||
</Button>
|
||||
<DialogClose :as-child="true">
|
||||
<Button variant="outline" size="icon">
|
||||
<X />
|
||||
<X/>
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</div>
|
||||
<div class="flex items-center justify-center overflow-hidden *:max-h-[80vh] *:max-w-[80vw] *:w-full *:h-full *:object-contain">
|
||||
<slot />
|
||||
<div
|
||||
class="flex items-center justify-center overflow-hidden *:max-h-[80vh] *:max-w-[80vw] *:w-full *:h-full *:object-contain"
|
||||
>
|
||||
<slot/>
|
||||
</div>
|
||||
<DialogDescription class="flex items-center justify-center">
|
||||
<Card v-if="attachment.description" class="max-w-md max-h-48 overflow-auto text-sm">
|
||||
<Card
|
||||
v-if="attachment.description"
|
||||
class="max-w-md max-h-48 overflow-auto text-sm"
|
||||
>
|
||||
<p>{{ attachment.description }}</p>
|
||||
</Card>
|
||||
</DialogDescription>
|
||||
|
|
@ -1,13 +1,17 @@
|
|||
<template>
|
||||
<Base :attachment="attachment">
|
||||
<audio :src="attachment.url" :alt="attachment.description ?? undefined" controls />
|
||||
</Base>
|
||||
<AttachmentBase :attachment="attachment">
|
||||
<audio
|
||||
:src="attachment.url"
|
||||
:alt="attachment.description ?? undefined"
|
||||
controls
|
||||
/>
|
||||
</AttachmentBase>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { Attachment } from "@versia/client/schemas";
|
||||
import type { z } from "zod";
|
||||
import Base from "./base.vue";
|
||||
import AttachmentBase from "./attachment-base.vue";
|
||||
|
||||
const { attachment } = defineProps<{
|
||||
attachment: z.infer<typeof Attachment>;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,19 @@
|
|||
<template>
|
||||
<Base :attachment="attachment" lightbox>
|
||||
<div class="flex flex-col items-center justify-center min-h-48 text-sm gap-2">
|
||||
<File class="size-12" />
|
||||
<AttachmentBase :attachment="attachment" lightbox>
|
||||
<div
|
||||
class="flex flex-col items-center justify-center min-h-48 text-sm gap-2"
|
||||
>
|
||||
<File class="size-12"/>
|
||||
<span>File attachment</span>
|
||||
</div>
|
||||
</Base>
|
||||
</AttachmentBase>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { Attachment } from "@versia/client/schemas";
|
||||
import { File } from "lucide-vue-next";
|
||||
import type { z } from "zod";
|
||||
import Base from "./base.vue";
|
||||
import AttachmentBase from "./attachment-base.vue";
|
||||
|
||||
const { attachment } = defineProps<{
|
||||
attachment: z.infer<typeof Attachment>;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
<template>
|
||||
<Base :attachment="attachment" lightbox>
|
||||
<img :src="attachment.url" :alt="attachment.description ?? undefined" />
|
||||
</Base>
|
||||
<AttachmentBase :attachment="attachment" lightbox>
|
||||
<img :src="attachment.url" :alt="attachment.description ?? undefined">
|
||||
</AttachmentBase>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { Attachment } from "@versia/client/schemas";
|
||||
import type { z } from "zod";
|
||||
import Base from "./base.vue";
|
||||
import AttachmentBase from "./attachment-base.vue";
|
||||
|
||||
const { attachment } = defineProps<{
|
||||
attachment: z.infer<typeof Attachment>;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,19 @@
|
|||
<template>
|
||||
<Base :attachment="attachment">
|
||||
<video :src="attachment.url" :alt="attachment.description ?? undefined" controls />
|
||||
</Base>
|
||||
<AttachmentBase :attachment="attachment">
|
||||
<video
|
||||
:src="attachment.url"
|
||||
:alt="attachment.description ?? undefined"
|
||||
controls
|
||||
>
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</AttachmentBase>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { Attachment } from "@versia/client/schemas";
|
||||
import type { z } from "zod";
|
||||
import Base from "./base.vue";
|
||||
import AttachmentBase from "./attachment-base.vue";
|
||||
|
||||
const { attachment } = defineProps<{
|
||||
attachment: z.infer<typeof Attachment>;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,18 @@
|
|||
<p class="text-sm leading-6 wrap-anywhere">
|
||||
{{ contentWarning || m.sour_seemly_bird_hike() }}
|
||||
</p>
|
||||
<Button @click="hidden = !hidden" variant="outline" size="sm" class="col-span-2">
|
||||
<Button
|
||||
@click="hidden = !hidden"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="col-span-2"
|
||||
>
|
||||
{{ hidden ? m.bald_direct_turtle_win() :
|
||||
m.known_flaky_cockroach_dash() }} {{ characterCount > 0 ? ` (${characterCount} characters` : "" }}{{
|
||||
attachmentCount > 0 ? `${characterCount > 0 ? " · " : " ("}${attachmentCount} file(s)` : "" }}{{ (characterCount > 0 || attachmentCount > 0) ? ")" : "" }}
|
||||
m.known_flaky_cockroach_dash() }}
|
||||
{{ characterCount > 0 ? ` (${characterCount} characters` : "" }}
|
||||
{{
|
||||
attachmentCount > 0 ? `${characterCount > 0 ? " · " : " ("}${attachmentCount} file(s)` : "" }}
|
||||
{{ (characterCount > 0 || attachmentCount > 0) ? ")" : "" }}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,28 @@
|
|||
<template>
|
||||
<ContentWarning v-if="(sensitive || contentWarning) && preferences.show_content_warning" :content-warning="contentWarning" :character-count="characterCount ?? 0" :attachment-count="attachments.length" v-model="hidden" />
|
||||
<ContentWarning
|
||||
v-if="(sensitive || contentWarning) && preferences.show_content_warning"
|
||||
:content-warning="contentWarning"
|
||||
:character-count="characterCount ?? 0"
|
||||
:attachment-count="attachments.length"
|
||||
v-model="hidden"
|
||||
/>
|
||||
|
||||
<OverflowGuard v-if="content" :character-count="characterCount" :class="(hidden && preferences.show_content_warning) && 'hidden'">
|
||||
<OverflowGuard
|
||||
v-if="content"
|
||||
:character-count="characterCount"
|
||||
:class="(hidden && preferences.show_content_warning) && 'hidden'"
|
||||
>
|
||||
<Prose v-html="content" v-render-emojis="emojis"></Prose>
|
||||
</OverflowGuard>
|
||||
|
||||
<Attachments v-if="attachments.length > 0" :attachments="attachments" :class="(hidden && preferences.show_content_warning) && 'hidden'" />
|
||||
<Attachments
|
||||
v-if="attachments.length > 0"
|
||||
:attachments="attachments"
|
||||
:class="(hidden && preferences.show_content_warning) && 'hidden'"
|
||||
/>
|
||||
|
||||
<div v-if="quote" class="mt-4 rounded border overflow-hidden">
|
||||
<Note :note="quote" :hide-actions="true" :small-layout="true" />
|
||||
<Note :note="quote" :hide-actions="true" :small-layout="true"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,36 +1,61 @@
|
|||
<template>
|
||||
<div class="rounded grid grid-cols-[auto_1fr_auto] items-center gap-3">
|
||||
<HoverCard v-model:open="popupOpen" @update:open="() => {
|
||||
<HoverCard
|
||||
v-model:open="popupOpen"
|
||||
@update:open="() => {
|
||||
if (!preferences.popup_avatar_hover) {
|
||||
popupOpen = false;
|
||||
}
|
||||
}" :open-delay="2000">
|
||||
}"
|
||||
:open-delay="2000"
|
||||
>
|
||||
<HoverCardTrigger :as-child="true">
|
||||
<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" />
|
||||
<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"
|
||||
/>
|
||||
</NuxtLink>
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent class="w-96">
|
||||
<SmallCard :account="author" />
|
||||
<SmallCard :account="author"/>
|
||||
</HoverCardContent>
|
||||
</HoverCard>
|
||||
<Col
|
||||
:class="smallLayout && 'text-sm'">
|
||||
<Text class="font-semibold" v-render-emojis="author.emojis">{{
|
||||
<Column :class="smallLayout && 'text-sm'">
|
||||
<Text class="font-semibold" v-render-emojis="author.emojis">
|
||||
{{
|
||||
author.display_name
|
||||
}}</Text>
|
||||
}}
|
||||
</Text>
|
||||
<div class="-mt-1">
|
||||
<Address as="span" :username="username" :domain="instance" />
|
||||
<Address as="span" :username="username" :domain="instance"/>
|
||||
·
|
||||
<Text as="span" muted class="ml-auto tracking-normal" :title="fullTime">{{ timeAgo }}</Text>
|
||||
<Text
|
||||
as="span"
|
||||
muted
|
||||
class="ml-auto tracking-normal"
|
||||
:title="fullTime"
|
||||
>
|
||||
{{ timeAgo }}
|
||||
</Text>
|
||||
</div>
|
||||
</Col>
|
||||
</Column>
|
||||
<div v-if="!smallLayout">
|
||||
<NuxtLink :href="noteUrlAsPath" class="text-xs text-muted-foreground"
|
||||
:title="visibilities[visibility].text">
|
||||
<component :is="visibilities[visibility].icon" class="size-4" />
|
||||
<NuxtLink
|
||||
:href="noteUrlAsPath"
|
||||
class="text-xs text-muted-foreground"
|
||||
:title="visibilities[visibility].text"
|
||||
>
|
||||
<component :is="visibilities[visibility].icon" class="size-4"/>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -49,7 +74,7 @@ import { getLocale } from "~~/paraglide/runtime";
|
|||
import Address from "../profiles/address.vue";
|
||||
import Avatar from "../profiles/avatar.vue";
|
||||
import SmallCard from "../profiles/small-card.vue";
|
||||
import Col from "../typography/layout/col.vue";
|
||||
import Column from "../typography/layout/col.vue";
|
||||
import Text from "../typography/text.vue";
|
||||
import {
|
||||
HoverCard,
|
||||
|
|
|
|||
|
|
@ -79,57 +79,71 @@ const _delete = async () => {
|
|||
<template>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<slot />
|
||||
<slot/>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent class="min-w-56">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem v-if="authorIsMe" as="button" @click="emit('edit')">
|
||||
<Pencil />
|
||||
<DropdownMenuItem
|
||||
v-if="authorIsMe"
|
||||
as="button"
|
||||
@click="emit('edit')"
|
||||
>
|
||||
<Pencil/>
|
||||
{{ m.front_lime_grizzly_persist() }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem as="button" @click="copyText(apiNoteString)">
|
||||
<Code />
|
||||
<Code/>
|
||||
{{ m.yummy_moving_scallop_sail() }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem as="button" @click="copyText(noteId)">
|
||||
<Hash />
|
||||
<Hash/>
|
||||
{{ m.sunny_zany_jellyfish_pop() }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuSeparator/>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem as="button" @click="copyText(url)">
|
||||
<Link />
|
||||
<Link/>
|
||||
{{ m.ago_new_pelican_drip() }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem as="button" v-if="isRemote && remoteUrl" @click="copyText(remoteUrl)">
|
||||
<Link />
|
||||
<DropdownMenuItem
|
||||
as="button"
|
||||
v-if="isRemote && remoteUrl"
|
||||
@click="copyText(remoteUrl)"
|
||||
>
|
||||
<Link/>
|
||||
{{ m.solid_witty_zebra_walk() }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem as="a" v-if="isRemote" target="_blank" rel="noopener noreferrer" :href="remoteUrl">
|
||||
<ExternalLink />
|
||||
<DropdownMenuItem
|
||||
as="a"
|
||||
v-if="isRemote"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
:href="remoteUrl"
|
||||
>
|
||||
<ExternalLink/>
|
||||
{{ m.active_trite_lark_inspire() }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator v-if="authorIsMe" />
|
||||
<DropdownMenuSeparator v-if="authorIsMe"/>
|
||||
<DropdownMenuGroup v-if="authorIsMe">
|
||||
<DropdownMenuItem as="button" :disabled="true">
|
||||
<Delete />
|
||||
<Delete/>
|
||||
{{ m.real_green_clownfish_pet() }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem as="button" @click="_delete">
|
||||
<Trash />
|
||||
<Trash/>
|
||||
{{ m.tense_quick_cod_favor() }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator v-if="authStore.isSignedIn && !authorIsMe" />
|
||||
<DropdownMenuSeparator v-if="authStore.isSignedIn && !authorIsMe"/>
|
||||
<DropdownMenuGroup v-if="authStore.isSignedIn && !authorIsMe">
|
||||
<DropdownMenuItem as="button" :disabled="true">
|
||||
<Flag />
|
||||
<Flag/>
|
||||
{{ m.great_few_jaguar_rise() }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem as="button" @click="blockUser(authorId)">
|
||||
<Ban />
|
||||
<Ban/>
|
||||
{{ m.misty_soft_sparrow_vent() }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,12 @@
|
|||
: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" />
|
||||
<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
|
||||
|
|
|
|||
|
|
@ -1,18 +1,29 @@
|
|||
<template>
|
||||
<div ref="container" class="overflow-y-hidden relative duration-200" :style="{
|
||||
<div
|
||||
ref="container"
|
||||
class="overflow-y-hidden relative duration-200"
|
||||
:style="{
|
||||
maxHeight: collapsed ? '18rem' : `${container?.scrollHeight}px`,
|
||||
}">
|
||||
<slot />
|
||||
<div v-if="isOverflowing && collapsed"
|
||||
class="absolute inset-x-0 bottom-0 h-36 bg-gradient-to-t from-black/5 to-transparent rounded-b"></div>
|
||||
<Button v-if="isOverflowing" @click="collapsed = !collapsed"
|
||||
class="absolute bottom-2 right-1/2 translate-x-1/2">{{
|
||||
}"
|
||||
>
|
||||
<slot/>
|
||||
<div
|
||||
v-if="isOverflowing && collapsed"
|
||||
class="absolute inset-x-0 bottom-0 h-36 bg-gradient-to-t from-black/5 to-transparent rounded-b"
|
||||
></div>
|
||||
<Button
|
||||
v-if="isOverflowing"
|
||||
@click="collapsed = !collapsed"
|
||||
class="absolute bottom-2 right-1/2 translate-x-1/2"
|
||||
>
|
||||
{{
|
||||
collapsed
|
||||
? `${m.lazy_honest_mammoth_bump()}${formattedCharacterCount ? ` • ${m.dark_spare_goldfish_charm({
|
||||
count: formattedCharacterCount,
|
||||
})}` : ""}`
|
||||
: m.that_misty_mule_arrive()
|
||||
}}</Button>
|
||||
}}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
<template>
|
||||
<div :class="[
|
||||
<div
|
||||
:class="[
|
||||
'prose prose-sm block relative dark:prose-invert duration-200 !max-w-full break-words prose-a:no-underline hover:prose-a:underline',
|
||||
$style.content,
|
||||
]">
|
||||
<slot />
|
||||
]"
|
||||
>
|
||||
<slot/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
<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" />
|
||||
<Reaction
|
||||
v-for="reaction in reactions"
|
||||
:key="reaction.name"
|
||||
:reaction="reaction"
|
||||
:emoji="emojis.find(e => `:${e.shortcode}:` === reaction.name)"
|
||||
:status-id="statusId"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
<template>
|
||||
<div class="sticky top-2 z-10 flex items-center justify-center p-2">
|
||||
<Badge variant="secondary">
|
||||
{{ categoryName }}
|
||||
</Badge>
|
||||
<Badge variant="secondary">{{ categoryName }}</Badge>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,17 @@
|
|||
<template>
|
||||
<div class="p-2 text-sm font-semibold border-0 rounded-none text-center flex flex-row items-center gap-2 truncate">
|
||||
<img v-if="(emoji as InferredEmoji)?.url" :src="(emoji as InferredEmoji)?.url"
|
||||
:alt="(emoji as InferredEmoji)?.shortcode" class="h-8 align-middle inline not-prose" />
|
||||
<span v-else-if="(emoji as UnicodeEmoji)?.unicode" class="text-2xl align-middle inline not-prose">
|
||||
<div
|
||||
class="p-2 text-sm font-semibold border-0 rounded-none text-center flex flex-row items-center gap-2 truncate"
|
||||
>
|
||||
<img
|
||||
v-if="(emoji as InferredEmoji)?.url"
|
||||
:src="(emoji as InferredEmoji)?.url"
|
||||
:alt="(emoji as InferredEmoji)?.shortcode"
|
||||
class="h-8 align-middle inline not-prose"
|
||||
>
|
||||
<span
|
||||
v-else-if="(emoji as UnicodeEmoji)?.unicode"
|
||||
class="text-2xl align-middle inline not-prose"
|
||||
>
|
||||
{{ (emoji as UnicodeEmoji)?.unicode }}
|
||||
</span>
|
||||
{{ (emoji as InferredEmoji)?.shortcode || (emoji as UnicodeEmoji)?.shortcode }}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,22 @@
|
|||
<template>
|
||||
<Button @focus="() => emit('select', emoji)" @mouseenter="() => emit('select', emoji)" @click="() => emit('pick', emoji)" size="icon" variant="ghost"
|
||||
class="size-12">
|
||||
<img v-if="(emoji as InferredEmoji).url" :src="(emoji as InferredEmoji).url"
|
||||
:alt="(emoji as InferredEmoji).shortcode" class="h-8 align-middle inline not-prose" />
|
||||
<span v-else-if="(emoji as UnicodeEmoji).unicode" class="text-2xl align-middle inline not-prose">
|
||||
<Button
|
||||
@focus="() => emit('select', emoji)"
|
||||
@mouseenter="() => emit('select', emoji)"
|
||||
@click="() => emit('pick', emoji)"
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
class="size-12"
|
||||
>
|
||||
<img
|
||||
v-if="(emoji as InferredEmoji).url"
|
||||
:src="(emoji as InferredEmoji).url"
|
||||
:alt="(emoji as InferredEmoji).shortcode"
|
||||
class="h-8 align-middle inline not-prose"
|
||||
>
|
||||
<span
|
||||
v-else-if="(emoji as UnicodeEmoji).unicode"
|
||||
class="text-2xl align-middle inline not-prose"
|
||||
>
|
||||
{{ (emoji as UnicodeEmoji).unicode }}
|
||||
</span>
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -1,31 +1,57 @@
|
|||
<template>
|
||||
<Popover v-model:open="open">
|
||||
<PopoverTrigger as-child>
|
||||
<slot />
|
||||
<slot/>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="p-0 w-fit">
|
||||
<div class="grid-cols-[minmax(0,1fr)_auto] gap-0 grid divide-x *:h-112 *:overflow-y-auto"
|
||||
orientation="vertical">
|
||||
<div class="grid grid-rows-[auto_minmax(0,1fr)_auto] gap-0" ref="emojiContainer">
|
||||
<div
|
||||
class="grid-cols-[minmax(0,1fr)_auto] gap-0 grid divide-x *:h-112 *:overflow-y-auto"
|
||||
orientation="vertical"
|
||||
>
|
||||
<div
|
||||
class="grid grid-rows-[auto_minmax(0,1fr)_auto] gap-0"
|
||||
ref="emojiContainer"
|
||||
>
|
||||
<div class="p-2">
|
||||
<Input placeholder="Search" v-model="filter" />
|
||||
<Input placeholder="Search" v-model="filter"/>
|
||||
</div>
|
||||
<VList :data="virtualizedItems" #default="{ item }" class="relative" :style="{
|
||||
<VList
|
||||
:data="virtualizedItems"
|
||||
#default="{ item }"
|
||||
class="relative"
|
||||
:style="{
|
||||
width: `calc(var(--spacing) * ((12 * ${EMOJI_PER_ROW}) + (${EMOJI_PER_ROW} - 1)) + var(--spacing) * 4)`,
|
||||
}">
|
||||
<CategoryHeader :key="item.headerId" v-if="item.type === 'header'" :category-name="item.name" />
|
||||
<div v-else-if="item.type === 'emoji-row'" :key="item.rowId" class="flex gap-1 p-2">
|
||||
<Emoji v-for="emoji in item.emojis" :key="getEmojiKey(emoji)" :emoji="emoji"
|
||||
@select="(e) => selectedEmoji = e" @pick="e => {
|
||||
}"
|
||||
>
|
||||
<CategoryHeader
|
||||
:key="item.headerId"
|
||||
v-if="item.type === 'header'"
|
||||
:category-name="item.name"
|
||||
/>
|
||||
<div
|
||||
v-else-if="item.type === 'emoji-row'"
|
||||
:key="item.rowId"
|
||||
class="flex gap-1 p-2"
|
||||
>
|
||||
<Emoji
|
||||
v-for="emoji in item.emojis"
|
||||
:key="getEmojiKey(emoji)"
|
||||
:emoji="emoji"
|
||||
@select="(e) => selectedEmoji = e"
|
||||
@pick="e => {
|
||||
emit('pick', e); open = false;
|
||||
}" />
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
</VList>
|
||||
<EmojiDisplay :emoji="selectedEmoji" :style="{
|
||||
<EmojiDisplay
|
||||
:emoji="selectedEmoji"
|
||||
:style="{
|
||||
width: `calc(var(--spacing) * ((12 * ${EMOJI_PER_ROW}) + (${EMOJI_PER_ROW} - 1)) + var(--spacing) * 4)`,
|
||||
}" />
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
<Sidebar :categories="categories" @select="scrollToCategory" />
|
||||
<Sidebar :categories="categories" @select="scrollToCategory"/>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,23 @@
|
|||
<template>
|
||||
<div class="grid gap-1 bg-transparent p-2">
|
||||
<Button v-for="category in categories" :key="category.name" size="icon" variant="ghost" @click="() => emit('select', category)">
|
||||
<component v-if="category.groupId" :is="emojiGroupIconMap[category.groupId]" class="size-6 text-primary" />
|
||||
<img v-else-if="category.src" :src="category.src" class="size-6 align-middle inline not-prose" role="presentation" />
|
||||
<Button
|
||||
v-for="category in categories"
|
||||
:key="category.name"
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
@click="() => emit('select', category)"
|
||||
>
|
||||
<component
|
||||
v-if="category.groupId"
|
||||
:is="emojiGroupIconMap[category.groupId]"
|
||||
class="size-6 text-primary"
|
||||
/>
|
||||
<img
|
||||
v-else-if="category.src"
|
||||
:src="category.src"
|
||||
class="size-6 align-middle inline not-prose"
|
||||
role="presentation"
|
||||
>
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,23 +1,38 @@
|
|||
<template>
|
||||
<HoverCard @update:open="(open) => open && accounts === null && refreshReactions()">
|
||||
<HoverCard
|
||||
@update:open="(open) => open && accounts === null && refreshReactions()"
|
||||
>
|
||||
<HoverCardTrigger as-child>
|
||||
<Button @click="reaction.me ? !reaction.remote && unreact() : !reaction.remote && react()" :variant="reaction.me ? 'secondary' : reaction.remote ? 'ghost' : 'outline'" 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>
|
||||
<Button
|
||||
@click="reaction.me ? !reaction.remote && unreact() : !reaction.remote && react()"
|
||||
:variant="reaction.me ? 'secondary' : reaction.remote ? 'ghost' : 'outline'"
|
||||
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" />
|
||||
<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" />
|
||||
<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>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
<template>
|
||||
<NuxtLink :href="urlAsPath">
|
||||
<Card class="flex-row px-2 py-1 items-center gap-2 hover:bg-muted duration-100 text-sm">
|
||||
<Repeat class="size-4 text-primary" />
|
||||
<Avatar class="size-6 border" :src="avatar" :name="displayName" />
|
||||
<span class="font-semibold" v-render-emojis="emojis">{{ displayName }}</span>
|
||||
<Card
|
||||
class="flex-row px-2 py-1 items-center gap-2 hover:bg-muted duration-100 text-sm"
|
||||
>
|
||||
<Repeat class="size-4 text-primary"/>
|
||||
<Avatar class="size-6 border" :src="avatar" :name="displayName"/>
|
||||
<span class="font-semibold" v-render-emojis="emojis"
|
||||
>{{ displayName }}</span
|
||||
>
|
||||
{{ m.large_vivid_horse_catch() }}
|
||||
</Card>
|
||||
</NuxtLink>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue