diff --git a/.changeset/tough-buttons-speak.md b/.changeset/tough-buttons-speak.md
new file mode 100644
index 000000000..fd943297f
--- /dev/null
+++ b/.changeset/tough-buttons-speak.md
@@ -0,0 +1,5 @@
+---
+"nostrudel": minor
+---
+
+Add user likes tab under profile view
diff --git a/src/app.tsx b/src/app.tsx
index da9679389..675eda6cd 100644
--- a/src/app.tsx
+++ b/src/app.tsx
@@ -34,6 +34,7 @@ import UserMediaTab from "./views/user/media";
import ToolsHomeView from "./views/tools";
import Nip19ToolsView from "./views/tools/nip19";
import UserAboutTab from "./views/user/about";
+import UserLikesTab from "./views/user/likes";
const LiveStreamsTab = React.lazy(() => import("./views/streams"));
const StreamView = React.lazy(() => import("./views/streams/stream"));
@@ -73,6 +74,7 @@ const router = createHashRouter([
{ path: "notes", element: },
{ path: "media", element: },
{ path: "zaps", element: },
+ { path: "likes", element: },
{ path: "followers", element: },
{ path: "following", element: },
{ path: "relays", element: },
diff --git a/src/views/user/index.tsx b/src/views/user/index.tsx
index 031c4c979..0ef57dfb9 100644
--- a/src/views/user/index.tsx
+++ b/src/views/user/index.tsx
@@ -46,6 +46,7 @@ const tabs = [
{ label: "Media", path: "media" },
{ label: "Zaps", path: "zaps" },
{ label: "Following", path: "following" },
+ { label: "Likes", path: "likes" },
{ label: "Relays", path: "relays" },
{ label: "Reports", path: "reports" },
{ label: "Followers", path: "followers" },
diff --git a/src/views/user/likes.tsx b/src/views/user/likes.tsx
new file mode 100644
index 000000000..495c63f30
--- /dev/null
+++ b/src/views/user/likes.tsx
@@ -0,0 +1,79 @@
+import { useRef } from "react";
+import { useOutletContext } from "react-router-dom";
+import { Box, Flex, SkeletonText, Spacer, Text } from "@chakra-ui/react";
+import { Kind } from "nostr-tools";
+import { getReferences, truncatedId } from "../../helpers/nostr-event";
+import { useTimelineLoader } from "../../hooks/use-timeline-loader";
+import { NostrEvent } from "../../types/nostr-event";
+import { useAdditionalRelayContext } from "../../providers/additional-relay-context";
+import { useReadRelayUrls } from "../../hooks/use-client-relays";
+import TimelineActionAndStatus from "../../components/timeline-action-and-status";
+import useSubject from "../../hooks/use-subject";
+import IntersectionObserverProvider, { useRegisterIntersectionEntity } from "../../providers/intersection-observer";
+import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
+import useSingleEvent from "../../hooks/use-single-event";
+import { Note } from "../../components/note";
+import { TrustProvider } from "../../providers/trust";
+import { UserAvatar } from "../../components/user-avatar";
+import { UserLink } from "../../components/user-link";
+import { NoteMenu } from "../../components/note/note-menu";
+
+const Like = ({ event }: { event: NostrEvent }) => {
+ const ref = useRef(null);
+ useRegisterIntersectionEntity(ref, event.id);
+
+ const contextRelays = useAdditionalRelayContext();
+ const readRelays = useReadRelayUrls(contextRelays);
+
+ const refs = getReferences(event);
+ const eventId: string | undefined = refs.events[0];
+ const { event: note } = useSingleEvent(eventId, readRelays);
+
+ var content = <>>;
+ if (!note) return ;
+
+ if (note.kind === Kind.Text) {
+ content = (
+ <>
+
+
+
+ {event.content === "+" ? "liked" : "reacted with " + event.content}
+
+
+
+
+
+ >
+ );
+ } else content = <>Unknown note type {note.kind}>;
+
+ return {content};
+};
+
+export default function UserLikesTab() {
+ const { pubkey } = useOutletContext() as { pubkey: string };
+ const contextRelays = useAdditionalRelayContext();
+ const readRelays = useReadRelayUrls(contextRelays);
+
+ const timeline = useTimelineLoader(`${truncatedId(pubkey)}-likes`, readRelays, { authors: [pubkey], kinds: [7] });
+
+ const lines = useSubject(timeline.timeline);
+
+ const scrollBox = useRef(null);
+ const callback = useTimelineCurserIntersectionCallback(timeline);
+
+ return (
+
+
+
+ {lines.map((event) => (
+
+ ))}
+
+
+
+
+
+ );
+}