refactor: ♻️ More work on rewriting notes

This commit is contained in:
Jesse Wierzbinski 2024-11-30 16:21:16 +01:00
parent d29f181000
commit 8cc4ff1348
No known key found for this signature in database
20 changed files with 514 additions and 63 deletions

View file

@ -0,0 +1,45 @@
<template>
<div class="flex flex-row w-full items-stretch justify-around text-sm *:max-w-28 *:w-full *:text-muted-foreground">
<Button variant="ghost">
<Reply class="size-5 text-primary" />
{{ numberFormat(replyCount) }}
</Button>
<Button variant="ghost">
<Heart class="size-5 text-primary" />
{{ numberFormat(likeCount) }}
</Button>
<Button variant="ghost">
<Repeat class="size-5 text-primary" />
{{ numberFormat(reblogCount) }}
</Button>
<Button variant="ghost">
<Quote class="size-5 text-primary" />
</Button>
<Menu>
<Button variant="ghost">
<Ellipsis class="size-5 text-primary" />
</Button>
</Menu>
</div>
</template>
<script lang="ts" setup>
import { Ellipsis, Heart, Quote, Repeat, Reply } from "lucide-vue-next";
import { Button } from "~/components/ui/button";
import Menu from "./menu.vue";
defineProps<{
replyCount: number;
likeCount: number;
reblogCount: number;
}>();
const numberFormat = (number = 0) =>
number !== 0
? new Intl.NumberFormat(undefined, {
notation: "compact",
compactDisplay: "short",
maximumFractionDigits: 1,
}).format(number)
: undefined;
</script>

View file

@ -1,5 +1,5 @@
<template>
<div :class="['prose block relative dark:prose-invert duration-200 !max-w-full break-words', $style.content]" v-html="content">
<div :class="['prose block relative dark:prose-invert duration-200 !max-w-full break-words prose-a:no-underline prose-a:hover:underline', $style.content]" v-html="content">
</div>
</template>

View file

@ -1,23 +1,29 @@
<template>
<div class="rounded flex flex-row gap-4">
<Avatar class="size-14 rounded border border-card">
<AvatarImage :src="avatar" alt="" />
<AvatarFallback class="rounded-lg"> AA </AvatarFallback>
</Avatar>
<div class="rounded flex flex-row gap-3">
<div class="relative">
<Avatar class="size-14 rounded-md border border-card">
<AvatarImage :src="avatar" alt="" />
<AvatarFallback class="rounded-lg"> AA </AvatarFallback>
</Avatar>
<Avatar v-if="cornerAvatar" class="size-6 rounded border absolute -bottom-1 -right-1">
<AvatarImage :src="cornerAvatar" alt="" />
<AvatarFallback class="rounded-lg"> AA </AvatarFallback>
</Avatar>
</div>
<div class="flex flex-col gap-0.5 justify-center flex-1 text-left leading-tight">
<span class="truncate font-semibold">{{
displayName
}}</span>
<span class="truncate text-sm">
}}</span>
<span class="truncate text-sm tracking-tight">
<CopyableText :text="acct">
<span
class="font-semibold bg-gradient-to-tr from-pink-300 via-purple-300 to-indigo-400 text-transparent bg-clip-text">
class="font-semibold bg-gradient-to-tr from-pink-700 dark:from-indigo-400 via-purple-700 dark:via-purple-400 to-indigo-700 dark:to-indigo-400 text-transparent bg-clip-text">
@{{ username }}
</span>
<span class="text-muted-foreground">{{ instance && "@" }}{{ instance }}</span>
</CopyableText>
&middot;
<span class="text-muted-foreground ml-auto" :title="fullTime">{{ timeAgo }}</span>
<span class="text-muted-foreground ml-auto tracking-normal" :title="fullTime">{{ timeAgo }}</span>
</span>
</div>
<div class="flex flex-col gap-1 justify-center items-end">
@ -35,6 +41,7 @@ import CopyableText from "./copyable-text.vue";
const { acct, createdAt } = defineProps<{
avatar: string;
cornerAvatar?: string;
acct: string;
displayName: string;
visibility: StatusVisibility;

84
components/notes/menu.vue Normal file
View file

@ -0,0 +1,84 @@
<script setup lang="ts">
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Ban,
Code,
Delete,
ExternalLink,
Link,
MessageSquare,
Pencil,
Trash,
} from "lucide-vue-next";
</script>
<template>
<DropdownMenu>
<DropdownMenuTrigger as-child>
<slot />
</DropdownMenuTrigger>
<DropdownMenuContent class="w-56">
<DropdownMenuLabel>Note Actions</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>
<Pencil class="mr-2 size-4" />
<span>Edit</span>
<DropdownMenuShortcut>E</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem>
<Code class="mr-2 size-4" />
<span>Copy API data</span>
<DropdownMenuShortcut>B</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem>
<Link class="mr-2 size-4" />
<span>Copy link</span>
<DropdownMenuShortcut>S</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem>
<Link class="mr-2 size-4" />
<span>Copy link (origin)</span>
<DropdownMenuShortcut>K</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem>
<ExternalLink class="mr-2 size-4" />
<span>Open on remote</span>
<DropdownMenuShortcut>F</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>
<Delete class="mr-2 size-4" />
<span>Delete and redraft</span>
</DropdownMenuItem>
<DropdownMenuItem>
<Trash class="mr-2 size-4" />
<span>Delete</span>
<DropdownMenuShortcut>D</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>
<MessageSquare class="mr-2 size-4" />
<span>Report</span>
</DropdownMenuItem>
<DropdownMenuItem>
<Ban class="mr-2 size-4" />
<span>Block user</span>
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</template>

View file

@ -1,26 +1,38 @@
<template>
<Card as="article" class="rounded-none border-0 hover:bg-muted/50 duration-200">
<Card as="article" class="rounded-none border-0 duration-200 shadow-none">
<CardHeader class="pb-4">
<Header :avatar="note.account.avatar" :acct="note.account.acct" :display-name="note.account.display_name"
:visibility="note.visibility" :url="accountUrl" :created-at="new Date(note.created_at)" />
<ReblogHeader v-if="!!note.reblog" :avatar="note.account.avatar"
:display-name="note.account.display_name" />
<Header :avatar="noteToUse.account.avatar" :corner-avatar="note.reblog ? note.account.avatar : undefined"
:acct="noteToUse.account.acct" :display-name="noteToUse.account.display_name"
:visibility="noteToUse.visibility" :url="accountUrl" :created-at="new Date(noteToUse.created_at)" />
</CardHeader>
<CardContent>
<Content :content="note.content" />
<Content :content="noteToUse.content" />
</CardContent>
<CardFooter>
<Actions :reply-count="noteToUse.replies_count" :like-count="noteToUse.favourites_count"
:reblog-count="noteToUse.reblogs_count" />
</CardFooter>
</Card>
</template>
<script setup lang="ts">
import type { Status } from "@versia/client/types";
import { Card, CardHeader } from "../ui/card";
import { Separator } from "../ui/separator";
import { Card, CardFooter, CardHeader } from "../ui/card";
import Actions from "./actions.vue";
import Content from "./content.vue";
import Header from "./header.vue";
import ReblogHeader from "./reblog-header.vue";
const { note } = defineProps<{
note: Status;
}>();
const url = `/@${note.account.acct}/${note.id}`;
const accountUrl = `/@${note.account.acct}`;
</script>
// Notes can be reblogs or quotes, in which case
// the actual thing to render is inside the reblog or quote
const noteToUse = note.reblog ? note.reblog : note.quote ? note.quote : note;
const url = `/@${noteToUse.account.acct}/${noteToUse.id}`;
const accountUrl = `/@${noteToUse.account.acct}`;
</script>

View file

@ -0,0 +1,21 @@
<template>
<div class="rounded border hover:bg-muted duration-100 text-sm flex flex-row items-center gap-2 px-2 py-1 mb-2">
<Repeat class="size-4 text-primary" />
<Avatar class="size-6 rounded border">
<AvatarImage :src="avatar" alt="" />
<AvatarFallback class="rounded-lg"> AA </AvatarFallback>
</Avatar>
<span class="font-semibold">{{ displayName }}</span>
reblogged
</div>
</template>
<script lang="ts" setup>
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Repeat } from "lucide-vue-next";
defineProps<{
avatar: string;
displayName: string;
}>();
</script>