From 67912eebdef81bea2b479150b7a38cee3234905f Mon Sep 17 00:00:00 2001 From: hzrd149 Date: Fri, 19 Apr 2024 08:37:29 -0500 Subject: [PATCH] add simple corrections feed --- package.json | 1 + src/app.tsx | 10 +-- src/components/diff/diff-viewer.tsx | 52 +++++++++++++++ src/views/other-stuff/apps.ts | 9 ++- .../tools/corrections/correction-card.tsx | 43 ++++++++++++ src/views/tools/corrections/index.tsx | 44 +++++++++++++ src/views/tools/wot-test.tsx | 66 ------------------- .../wiki/hooks/use-wiki-topic-timeline.tsx | 7 +- src/views/wiki/page.tsx | 6 +- yarn.lock | 32 +++++++++ 10 files changed, 196 insertions(+), 74 deletions(-) create mode 100644 src/components/diff/diff-viewer.tsx create mode 100644 src/views/tools/corrections/correction-card.tsx create mode 100644 src/views/tools/corrections/index.tsx delete mode 100644 src/views/tools/wot-test.tsx diff --git a/package.json b/package.json index 99867a2af..61e8dd156 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,7 @@ "nostr-wasm": "^0.1.0", "react": "^18.2.0", "react-chartjs-2": "^5.2.0", + "react-diff-viewer-continued": "^3.4.0", "react-dom": "^18.2.0", "react-error-boundary": "^4.0.11", "react-force-graph-2d": "^1.25.1", diff --git a/src/app.tsx b/src/app.tsx index 3d487e068..bd9bb5efb 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -77,12 +77,9 @@ import MediaServersView from "./views/relays/media-servers"; import NIP05RelaysView from "./views/relays/nip05"; import ContactListRelaysView from "./views/relays/contact-list"; import UserDMsTab from "./views/user/dms"; -import DMTimelineView from "./views/tools/dm-timeline"; import LoginNostrConnectView from "./views/signin/nostr-connect"; import ThreadsNotificationsView from "./views/notifications/threads"; import DVMFeedView from "./views/dvm-feed/feed"; -import TransformNoteView from "./views/tools/transform-note"; -import SatelliteCDNView from "./views/tools/satellite-cdn"; import OtherStuffView from "./views/other-stuff"; import { RouteProviders } from "./providers/route"; import LaunchpadView from "./views/launchpad"; @@ -97,13 +94,16 @@ const UserTracksTab = lazy(() => import("./views/user/tracks")); const UserVideosTab = lazy(() => import("./views/user/videos")); const ToolsHomeView = lazy(() => import("./views/tools")); -const WotTestView = lazy(() => import("./views/tools/wot-test")); const StreamModerationView = lazy(() => import("./views/streams/dashboard")); const NetworkMuteGraphView = lazy(() => import("./views/tools/network-mute-graph")); const NetworkDMGraphView = lazy(() => import("./views/tools/network-dm-graph")); const UnknownTimelineView = lazy(() => import("./views/tools/unknown-event-feed")); const EventConsoleView = lazy(() => import("./views/tools/event-console")); const EventPublisherView = lazy(() => import("./views/tools/event-publisher")); +const DMTimelineView = lazy(() => import("./views/tools/dm-timeline")); +const TransformNoteView = lazy(() => import("./views/tools/transform-note")); +const SatelliteCDNView = lazy(() => import("./views/tools/satellite-cdn")); +const CorrectionsFeedView = lazy(() => import("./views/tools/corrections")); const UserStreamsTab = lazy(() => import("./views/user/streams")); const StreamsView = lazy(() => import("./views/streams")); @@ -339,7 +339,6 @@ const router = createHashRouter([ path: "tools", children: [ { path: "", element: }, - { path: "wot-test", element: }, { path: "network-mute-graph", element: }, { path: "network-dm-graph", element: }, { path: "dm-timeline", element: }, @@ -348,6 +347,7 @@ const router = createHashRouter([ { path: "unknown", element: }, { path: "console", element: }, { path: "publisher", element: }, + { path: "corrections", element: }, ], }, { diff --git a/src/components/diff/diff-viewer.tsx b/src/components/diff/diff-viewer.tsx new file mode 100644 index 000000000..9ce21b96f --- /dev/null +++ b/src/components/diff/diff-viewer.tsx @@ -0,0 +1,52 @@ +import { ColorModeContext, useColorMode } from "@chakra-ui/react"; +import ReactDiffViewer from "react-diff-viewer-continued"; +import computeStyles, { ReactDiffViewerStylesOverride } from "react-diff-viewer-continued/lib/src/styles"; + +const fixedStyles: ReactDiffViewerStylesOverride = { + codeFold: { + height: "auto", + }, + contentText: { + lineHeight: "initial !important", + fontFamily: "inherit", + }, +}; + +// NOTE: This is a hack to hard code the emotion styles for react-diff-viewer-continued +// because the component was creating a new stylesheet for every instance (I guess the developer has no idea how to use @emotion/css) +let computed: ReturnType; +function getComputedStyles(dark = false) { + if (!computed) computed = computeStyles(fixedStyles, dark, "code-better"); + return computed; +} + +class FixedReactDiffViewer extends ReactDiffViewer { + static contextType = ColorModeContext; + + // @ts-expect-error + constructor(...args) { + // @ts-expect-error + super(...args); + // @ts-expect-error + this.computeStyles = () => { + // @ts-expect-error + return getComputedStyles(this.context.colorMode === "dark"); + }; + } +} + +export default function DiffViewer({ oldValue, newValue }: { oldValue: string; newValue: string }) { + const { colorMode } = useColorMode(); + + return ( + + ); +} diff --git a/src/views/other-stuff/apps.ts b/src/views/other-stuff/apps.ts index 5ce1c89b4..fdf672b7f 100644 --- a/src/views/other-stuff/apps.ts +++ b/src/views/other-stuff/apps.ts @@ -21,6 +21,7 @@ import Users01 from "../../components/icons/users-01"; import Film02 from "../../components/icons/film-02"; import MessageQuestionSquare from "../../components/icons/message-question-square"; import UploadCloud01 from "../../components/icons/upload-cloud-01"; +import Edit04 from "../../components/icons/edit-04"; export const internalApps: App[] = [ { @@ -113,7 +114,13 @@ export const internalTools: App[] = [ id: "publisher", to: "/tools/publisher ", }, - { title: "WoT Test", description: "Just a test for now", icon: Users01, id: "wot-test", to: "/tools/wot-test" }, + { + title: "Corrections Feed", + description: "A feed of post edits", + icon: Edit04, + id: "corrections", + to: "/tools/corrections ", + }, ]; export const externalTools: App[] = [ diff --git a/src/views/tools/corrections/correction-card.tsx b/src/views/tools/corrections/correction-card.tsx new file mode 100644 index 000000000..447ec0c7e --- /dev/null +++ b/src/views/tools/corrections/correction-card.tsx @@ -0,0 +1,43 @@ +import { Suspense, lazy, useMemo, useState } from "react"; +import { NostrEvent } from "nostr-tools"; +import { Button, ButtonGroup, Spinner, useColorMode } from "@chakra-ui/react"; + +import { isETag } from "../../../types/nostr-event"; +import useSingleEvent from "../../../hooks/use-single-event"; +import TimelineItem from "../../../components/timeline-page/generic-note-timeline/timeline-item"; +import DiffViewer from "../../../components/diff/diff-viewer"; + +export default function CorrectionCard({ correction }: { correction: NostrEvent }) { + const originalId = correction.tags.find(isETag)?.[1]; + const original = useSingleEvent(originalId); + + // NOTE: produces an invalid event + const modified = useMemo(() => original && { ...original, content: correction.content }, [correction, original]); + + const [show, setShow] = useState("modified"); + const showEvent = show === "original" ? original : modified; + + return ( +
+ + + + + + + {show === "diff" ? ( + }> + + + ) : ( + showEvent && + )} +
+ ); +} diff --git a/src/views/tools/corrections/index.tsx b/src/views/tools/corrections/index.tsx new file mode 100644 index 000000000..945f230f8 --- /dev/null +++ b/src/views/tools/corrections/index.tsx @@ -0,0 +1,44 @@ +import { Flex, Heading } from "@chakra-ui/react"; + +import VerticalPageLayout from "../../../components/vertical-page-layout"; +import { useReadRelays } from "../../../hooks/use-client-relays"; +import useSubject from "../../../hooks/use-subject"; +import useTimelineLoader from "../../../hooks/use-timeline-loader"; +import PeopleListProvider, { usePeopleListContext } from "../../../providers/local/people-list-provider"; +import BackButton from "../../../components/router/back-button"; +import PeopleListSelection from "../../../components/people-list-selection/people-list-selection"; +import CorrectionCard from "./correction-card"; + +function CorrectionsPage() { + const { listId, filter } = usePeopleListContext(); + const readRelays = useReadRelays(); + const timeline = useTimelineLoader( + `${listId}-corrections`, + readRelays, + filter ? [{ kinds: [1010], ...filter }] : undefined, + ); + + const corrections = useSubject(timeline.timeline); + + return ( + + + + Corrections + + + + {corrections.map((correction) => ( + + ))} + + ); +} + +export default function CorrectionsFeedView() { + return ( + + + + ); +} diff --git a/src/views/tools/wot-test.tsx b/src/views/tools/wot-test.tsx deleted file mode 100644 index d18689a29..000000000 --- a/src/views/tools/wot-test.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { memo, useMemo, useState } from "react"; -import { Button, Flex, Select, SimpleGrid, Text } from "@chakra-ui/react"; - -import useCurrentAccount from "../../hooks/use-current-account"; -import RequireCurrentAccount from "../../providers/route/require-current-account"; -import { useNetworkConnectionCount } from "../../hooks/use-user-network"; -import UserAvatarLink from "../../components/user/user-avatar-link"; -import UserLink from "../../components/user/user-link"; -import { ChevronLeftIcon } from "../../components/icons"; -import { useNavigate } from "react-router-dom"; -import VerticalPageLayout from "../../components/vertical-page-layout"; - -const User = memo(({ pubkey, count }: { pubkey: string; count: number }) => ( - - - - ({count}) - -)); - -function WotTestPage() { - const navigate = useNavigate(); - const account = useCurrentAccount()!; - const [range, setRange] = useState("50-100"); - - const network = useNetworkConnectionCount(account.pubkey); - const filteredPubkeys = useMemo(() => { - if (range.endsWith("+")) { - const min = parseInt(range.replace("+", "")); - return network.filter((p) => p.count > min); - } - const [min, max] = range.split("-").map((v) => parseInt(v)); - return network.filter((p) => p.count > min && p.count <= max); - }, [range, network]); - - return ( - - - - - - - {filteredPubkeys.map(({ pubkey, count }) => ( - - ))} - - - ); -} - -export default function WotTestView() { - return ( - - - - ); -} diff --git a/src/views/wiki/hooks/use-wiki-topic-timeline.tsx b/src/views/wiki/hooks/use-wiki-topic-timeline.tsx index 7be452576..25643e26f 100644 --- a/src/views/wiki/hooks/use-wiki-topic-timeline.tsx +++ b/src/views/wiki/hooks/use-wiki-topic-timeline.tsx @@ -1,7 +1,12 @@ +import { NostrEvent } from "nostr-tools"; import { WIKI_PAGE_KIND } from "../../../helpers/nostr/wiki"; import { useReadRelays } from "../../../hooks/use-client-relays"; import useTimelineLoader from "../../../hooks/use-timeline-loader"; +function noEmptyEvent(event: NostrEvent) { + return event.content.length > 0; +} + export default function useWikiTopicTimeline(topic: string) { const relays = useReadRelays(["wss://relay.wikifreedia.xyz/"]); @@ -9,6 +14,6 @@ export default function useWikiTopicTimeline(topic: string) { `wiki-${topic.toLocaleLowerCase()}-pages`, relays, [{ kinds: [WIKI_PAGE_KIND], "#d": [topic.toLocaleLowerCase()] }], - { eventFilter: (e) => e.content.length > 0 }, + { eventFilter: noEmptyEvent }, ); } diff --git a/src/views/wiki/page.tsx b/src/views/wiki/page.tsx index 3b46111a8..f28ae0d0d 100644 --- a/src/views/wiki/page.tsx +++ b/src/views/wiki/page.tsx @@ -1,5 +1,5 @@ import { NostrEvent } from "nostr-tools"; -import { Box, Card, Divider, Flex, Heading, Link, Spinner, Text } from "@chakra-ui/react"; +import { Box, ButtonGroup, Divider, Flex, Heading, Link, Spinner, Text } from "@chakra-ui/react"; import { Link as RouterLink } from "react-router-dom"; import useParamsAddressPointer from "../../hooks/use-params-address-pointer"; @@ -14,6 +14,7 @@ import useSubject from "../../hooks/use-subject"; import useWikiTopicTimeline from "./hooks/use-wiki-topic-timeline"; import WikiPageResult from "./components/wiki-page-result"; import Timestamp from "../../components/timestamp"; +import DebugEventButton from "../../components/debug-modal/debug-event-button"; function WikiPagePage({ page }: { page: NostrEvent }) { const topic = getPageTopic(page); @@ -34,6 +35,9 @@ function WikiPagePage({ page }: { page: NostrEvent }) { + + + {getPageTitle(page)} by - diff --git a/yarn.lock b/yarn.lock index 8892a5a97..9698ce814 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2145,6 +2145,17 @@ "@emotion/weak-memoize" "^0.3.1" stylis "4.2.0" +"@emotion/css@^11.11.2": + version "11.11.2" + resolved "https://registry.yarnpkg.com/@emotion/css/-/css-11.11.2.tgz#e5fa081d0c6e335352e1bc2b05953b61832dca5a" + integrity sha512-VJxe1ucoMYMS7DkiMdC2T7PWNbrEI0a39YRiyDvK2qq4lXwjRbVP/z4lpG+odCsRzadlR+1ywwrTzhdm5HNdew== + dependencies: + "@emotion/babel-plugin" "^11.11.0" + "@emotion/cache" "^11.11.0" + "@emotion/serialize" "^1.1.2" + "@emotion/sheet" "^1.2.2" + "@emotion/utils" "^1.2.1" + "@emotion/hash@^0.9.1": version "0.9.1" resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43" @@ -4102,6 +4113,11 @@ devlop@^1.0.0, devlop@^1.1.0: dependencies: dequal "^2.0.0" +diff@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" + integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -5600,6 +5616,11 @@ mdn-data@2.0.14: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== +memoize-one@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" + integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== + meow@^6.0.0: version "6.1.1" resolved "https://registry.yarnpkg.com/meow/-/meow-6.1.1.tgz#1ad64c4b76b2a24dfb2f635fddcadf320d251467" @@ -6439,6 +6460,17 @@ react-clientside-effect@^1.2.6: dependencies: "@babel/runtime" "^7.12.13" +react-diff-viewer-continued@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/react-diff-viewer-continued/-/react-diff-viewer-continued-3.4.0.tgz#0501ffb2b5ab740f88b9ae5f18771aa90d3803c2" + integrity sha512-kMZmUyb3Pv5L9vUtCfIGYsdOHs8mUojblGy1U1Sm0D7FhAOEsH9QhnngEIRo5hXWIPNGupNRJls1TJ6Eqx84eg== + dependencies: + "@emotion/css" "^11.11.2" + classnames "^2.3.2" + diff "^5.1.0" + memoize-one "^6.0.0" + prop-types "^15.8.1" + react-dnd-html5-backend@^16.0.1: version "16.0.1" resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz#87faef15845d512a23b3c08d29ecfd34871688b6"