diff --git a/components/cards/ChannelCard.tsx b/components/cards/ChannelCard.tsx
new file mode 100644
index 0000000..d09783c
--- /dev/null
+++ b/components/cards/ChannelCard.tsx
@@ -0,0 +1,43 @@
+import { Channel } from "revolt-api";
+import { Card, CardDescription, CardHeader, CardTitle } from "../ui/card";
+import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar";
+import Link from "next/link";
+
+export function ChannelCard({
+ channel,
+ subtitle,
+}: {
+ channel: Channel;
+ subtitle: string;
+}) {
+ if (channel.channel_type === "SavedMessages")
+ return
Refusing to render.
;
+
+ const name =
+ channel.channel_type === "DirectMessage" ? "Direct Message" : channel.name;
+
+ return (
+
+
+
+
+ {channel.channel_type !== "DirectMessage" && (
+
+ )}
+
+ {name
+ .split(" ")
+ .slice(0, 2)
+ .map((x) => String.fromCodePoint(x.codePointAt(0) ?? 32) ?? "")
+ .join("")}
+
+
+ {name}
+
+ {subtitle}
+
+
+ );
+}
diff --git a/components/cards/CompactMessage.tsx b/components/cards/CompactMessage.tsx
new file mode 100644
index 0000000..c51a8a8
--- /dev/null
+++ b/components/cards/CompactMessage.tsx
@@ -0,0 +1,124 @@
+"use client";
+
+import { Message, User } from "revolt-api";
+import { Avatar, AvatarImage } from "../ui/avatar";
+import { Image as ImageIcon, Pencil } from "lucide-react";
+import {
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogTitle,
+ AlertDialogTrigger,
+} from "../ui/alert-dialog";
+import dayjs from "dayjs";
+import { decodeTime } from "ulid";
+
+import calendarPlugin from "dayjs/plugin/calendar";
+import Link from "next/link";
+dayjs.extend(calendarPlugin);
+
+export function CompactMessage({
+ message,
+ users,
+ hideUser,
+}: {
+ message: Message;
+ users?: Record;
+ hideUser?: boolean;
+}) {
+ const user = users?.[message.author];
+
+ return (
+
+
+
+ e.button === 1 &&
+ window.open(`/panel/inspect/message/${message._id}`, "_blank")
+ }
+ >
+
+ {dayjs(decodeTime(message._id)).format("HH:mm")}
+
+ {!hideUser && (
+
+ {user?.avatar && (
+
+
+
+ )}
+ {user?.username}{" "}
+ {message.edited && (
+
+ )}
+
+ )}
+
+ {(message.attachments || message.embeds) && (
+
+ )}{" "}
+ {message.content ?? No text.}
+
+
+
+
+
+
+ {user?.avatar && (
+
+
+
+ )}{" "}
+ {user?.username}#{user?.discriminator}
+
+
+ {message.content && {message.content}}
+ {message.attachments?.map((attachment) =>
+ attachment.metadata.type === "Image" ? (
+
+
+
+ ) : (
+ "unsupported"
+ )
+ )}
+ {message.embeds?.map((embed, index) => (
+
+ {JSON.stringify(embed, null, 2)}
+
+ ))}
+
+
+
+
+ Inspect
+
+ Close
+
+
+
+ );
+}
diff --git a/components/cards/JsonCard.tsx b/components/cards/JsonCard.tsx
new file mode 100644
index 0000000..c329b39
--- /dev/null
+++ b/components/cards/JsonCard.tsx
@@ -0,0 +1,35 @@
+"use client";
+
+import { useState } from "react";
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from "../ui/card";
+import { Button } from "../ui/button";
+
+export function JsonCard({ obj }: { obj: any }) {
+ const [shown, setShown] = useState(false);
+
+ return (
+
+
+ Document
+ Raw JSON representation
+
+
+ {shown ? (
+
+ {JSON.stringify(obj, null, 2)}
+
+ ) : (
+
+ )}
+
+
+ );
+}
diff --git a/components/cards/MessageContextCard.tsx b/components/cards/MessageContextCard.tsx
index 1e1e507..6bb10f4 100644
--- a/components/cards/MessageContextCard.tsx
+++ b/components/cards/MessageContextCard.tsx
@@ -1,4 +1,4 @@
-import { Message, SnapshotContent, User } from "revolt-api";
+import { SnapshotContent } from "revolt-api";
import {
Card,
CardContent,
@@ -7,100 +7,7 @@ import {
CardTitle,
} from "../ui/card";
import { fetchUsersById } from "@/lib/db";
-import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar";
-import { Image as ImageIcon } from "lucide-react";
-import {
- AlertDialog,
- AlertDialogAction,
- AlertDialogCancel,
- AlertDialogContent,
- AlertDialogDescription,
- AlertDialogFooter,
- AlertDialogHeader,
- AlertDialogTitle,
- AlertDialogTrigger,
-} from "../ui/alert-dialog";
-
-function Message({
- message,
- users,
-}: {
- message: Message;
- users?: Record;
-}) {
- const user = users?.[message.author];
-
- return (
-
-
-
-
- {user?.avatar && (
-
-
-
- )}
- {user?.username}
-
-
- {(message.attachments || message.embeds) && (
-
- )}{" "}
- {message.content ?? No text.}
-
-
-
-
-
-
- {user?.avatar && (
-
-
-
- )}{" "}
- {user?.username}#{user?.discriminator}
-
-
- {message.content && {message.content}}
- {message.attachments?.map((attachment) =>
- attachment.metadata.type === "Image" ? (
-
-
-
- ) : (
- "unsupported"
- )
- )}
- {message.embeds?.map((embed, index) => (
-
- {JSON.stringify(embed, null, 2)}
-
- ))}
-
-
-
- Delete
- Close
-
-
-
- );
-}
+import { CompactMessage } from "./CompactMessage";
export async function MessageContextCard({
snapshot,
@@ -133,13 +40,13 @@ export async function MessageContextCard({
{[...(snapshot._prior_context ?? [])].reverse()?.map((message) => (
-
+
))}
-
+
{snapshot._leading_context?.map((message) => (
-
+
))}
diff --git a/components/cards/ReportCard.tsx b/components/cards/ReportCard.tsx
index e33673b..89b4d68 100644
--- a/components/cards/ReportCard.tsx
+++ b/components/cards/ReportCard.tsx
@@ -2,13 +2,22 @@ import Link from "next/link";
import { Report } from "revolt-api";
import { Card, CardDescription, CardHeader, CardTitle } from "../ui/card";
import { Badge } from "../ui/badge";
+import dayjs from "dayjs";
+import { decodeTime } from "ulid";
+
+import relativeTime from "dayjs/plugin/relativeTime";
+dayjs.extend(relativeTime);
export function ReportCard({ report }: { report: Report }) {
return (
-
+
{report.content.report_reason.includes("Illegal") && (
Urgent
@@ -18,7 +27,8 @@ export function ReportCard({ report }: { report: Report }) {
{report._id.toString().substring(20, 26)} ·{" "}
- {report.content.report_reason} · {report.content.type}
+ {report.content.report_reason} · {report.content.type}{" "}
+ · {dayjs(decodeTime(report._id)).fromNow()}
diff --git a/components/cards/ServerCard.tsx b/components/cards/ServerCard.tsx
new file mode 100644
index 0000000..ac3e69c
--- /dev/null
+++ b/components/cards/ServerCard.tsx
@@ -0,0 +1,35 @@
+import { Server } from "revolt-api";
+import { Card, CardDescription, CardHeader, CardTitle } from "../ui/card";
+import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar";
+import Link from "next/link";
+
+export function ServerCard({
+ server,
+ subtitle,
+}: {
+ server: Server;
+ subtitle: string;
+}) {
+ return (
+
+
+
+
+
+
+ {server.name
+ .split(" ")
+ .slice(0, 2)
+ .map((x) => String.fromCodePoint(x.codePointAt(0) ?? 32) ?? "")
+ .join("")}
+
+
+ {server.name}
+
+ {subtitle}
+
+
+ );
+}
diff --git a/components/cards/UserCard.tsx b/components/cards/UserCard.tsx
index a314e30..b331688 100644
--- a/components/cards/UserCard.tsx
+++ b/components/cards/UserCard.tsx
@@ -1,38 +1,38 @@
import { User } from "revolt-api";
import { Card, CardDescription, CardHeader, CardTitle } from "../ui/card";
import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar";
-import Link from "next/link";
+import { Badge } from "../ui/badge";
export function UserCard({ user, subtitle }: { user: User; subtitle: string }) {
return (
-
-
-
-
-
-
-
- {(user.display_name ?? user.username)
- .split(" ")
- .slice(0, 2)
- .join("")}
-
-
- {user.username}#{user.discriminator} {user.display_name}
-
- {subtitle}
-
-
-
+
+
+
+
+
+
+ {(user.display_name ?? user.username)
+ .split(" ")
+ .slice(0, 2)
+ .map((x) => String.fromCodePoint(x.codePointAt(0) ?? 32) ?? "")
+ .join("")}
+
+
+ {user.bot && Bot}{" "}
+ {user.username}#{user.discriminator} {user.display_name}
+
+ {subtitle}
+
+
);
}