diff options
Diffstat (limited to 'gui/src/pages')
| -rw-r--r-- | gui/src/pages/Feed.tsx | 56 | ||||
| -rw-r--r-- | gui/src/pages/Thread.tsx | 187 | ||||
| -rw-r--r-- | gui/src/pages/User.tsx | 40 |
3 files changed, 74 insertions, 209 deletions
diff --git a/gui/src/pages/Feed.tsx b/gui/src/pages/Feed.tsx index bb001d4..16a5ea1 100644 --- a/gui/src/pages/Feed.tsx +++ b/gui/src/pages/Feed.tsx @@ -8,13 +8,13 @@ import { useState } from "react"; import Composer from "@/components/composer/Composer"; import { ErrorPage } from "@/pages/Error"; import NostrFeed from "@/components/nostr/Feed"; +import { consolidateFeeds, disaggregate } from "@/logic/nostrill"; -type FeedType = "global" | "following" | "nostr"; +type FeedType = "urbit" | "following" | "nostr"; function Loader() { const params = useParams(); - console.log({ params }); if (!params.taip) return <FeedPage t="nostr" />; - if (params.taip === "global") return <FeedPage t={"global"} />; + // if (params.taip === "urbit") return <FeedPage t={"urbit"} />; if (params.taip === "following") return <FeedPage t={"following"} />; if (params.taip === "nostr") return <FeedPage t={"nostr"} />; // else if (param === FeedType.Rumors) return <Rumors />; @@ -27,10 +27,10 @@ function FeedPage({ t }: { t: FeedType }) { <> <div id="top-tabs"> <div - className={active === "global" ? "active" : ""} - onClick={() => setActive("global")} + className={active === "urbit" ? "active" : ""} + onClick={() => setActive("urbit")} > - Global + Urbit </div> <div className={active === "following" ? "active" : ""} @@ -47,8 +47,8 @@ function FeedPage({ t }: { t: FeedType }) { </div> <div id="feed-proper"> <Composer /> - {active === "global" ? ( - <Global /> + {active === "urbit" ? ( + <Urbit /> ) : active === "following" ? ( <Following /> ) : active === "nostr" ? ( @@ -58,40 +58,22 @@ function FeedPage({ t }: { t: FeedType }) { </> ); } -// {active === "global" ? ( -// <Global /> -// ) : active === "following" ? ( -// <Global /> -// ) : ( -// <Global /> -// )} -function Global() { - // const { api } = useLocalState(); - // const { isPending, data, refetch } = useQuery({ - // queryKey: ["globalFeed"], - // queryFn: () => { - // return api!.scryFeed(null, null); - // }, - // }); - // console.log(data, "scry feed data"); - // if (isPending) return <img className="x-center" src={spinner} />; - // else if ("bucun" in data) return <p>Error</p>; - // else return <Inner data={data} refetch={refetch} />; - return <p>Error</p>; +function Urbit() { + const following = useLocalState((s) => s.following); + const feed = disaggregate(following, "urbit"); + return ( + <div> + <PostList data={feed} refetch={() => {}} /> + </div> + ); } function Following() { - const following = useLocalState((s) => s.following2); - console.log({ following }); - - // console.log(data, "scry feed data"); - // if (isPending) return <img className="x-center" src={spinner} />; - // else if ("bucun" in data) return <p>Error</p>; - // else return <Inner data={data} refetch={refetch} />; - + const following = useLocalState((s) => s.following); + const feed = consolidateFeeds(following); return ( <div> - <PostList data={following} refetch={() => {}} /> + <PostList data={feed} refetch={() => {}} /> </div> ); } diff --git a/gui/src/pages/Thread.tsx b/gui/src/pages/Thread.tsx index fc215f2..a3d2234 100644 --- a/gui/src/pages/Thread.tsx +++ b/gui/src/pages/Thread.tsx @@ -1,167 +1,52 @@ import { useParams } from "wouter"; -import { useQuery } from "@tanstack/react-query"; import useLocalState from "@/state/state"; -import Icon from "@/components/Icon"; -import spinner from "@/assets/triangles.svg"; import { ErrorPage } from "@/pages/Error"; import "@/styles/trill.css"; import "@/styles/feed.css"; -import Post from "@/components/post/Post"; -import { extractThread, toFlat } from "@/logic/trill/helpers"; -import type { FullNode } from "@/types/trill"; -import Composer from "@/components/composer/Composer"; +import { stringToUser } from "@/logic/nostrill"; +import TrillThread from "@/components/trill/Thread"; +import NostrThread from "@/components/nostr/Thread"; +import { decodeNostrKey } from "@/logic/nostr"; + +export default function ThreadLoader() { + const { profiles, following } = useLocalState((s) => ({ + profiles: s.profiles, + following: s.following, + })); -export default function Thread() { const params = useParams<{ host: string; id: string }>(); const { host, id } = params; - const { api } = useLocalState((s) => ({ api: s.api })); - - async function fetchThread() { - return await api!.scryThread(host, id); - } - const { isPending, data, error } = useQuery({ - queryKey: ["thread", params.host, params.id], - queryFn: fetchThread, - enabled: !!api && !!params.host && !!params.id, - }); - - console.log({ data }); - if (!params.host || !params.id) { - return <ErrorPage msg="Invalid thread URL" />; - } - if (isPending) { + const uuser = stringToUser(host); + if ("error" in uuser) return <ErrorPage msg={uuser.error} />; + const feed = following.get(host); + const profile = profiles.get(host); + if ("urbit" in uuser.ok) return ( - <main> - <div className="thread-header"> - <h2>Loading Thread...</h2> - </div> - <div className="loading-container"> - <img className="x-center" src={spinner} alt="Loading" /> - </div> - </main> + <TrillThread + feed={feed} + profile={profile} + host={uuser.ok.urbit} + id={id} + /> ); - } - - if (error) { + if ("nostr" in uuser.ok) return ( - <main> - <div className="thread-header"> - <h2>Error Loading Thread</h2> - </div> - <ErrorPage msg={error.message || "Failed to load thread"} /> - </main> + <NostrThread + feed={feed} + profile={profile} + host={uuser.ok.nostr} + id={id} + /> ); - } - - if (!data || "error" in data) { - return ( - <main> - <div className="thread-header"> - <h2>Thread Not Found</h2> - </div> - <ErrorPage - msg={data?.error || "This thread doesn't exist or isn't accessible"} - /> - </main> - ); - } - console.log({ data }); - // TODO make Composer a modal when in Thread mode - return ( - <main> - <div className="thread-header"> - <div className="thread-nav"> - <button - className="back-btn" - onClick={() => window.history.back()} - title="Go back" - > - <Icon name="reply" size={16} /> - <span>Back to Feed</span> - </button> - </div> - <h2>Thread</h2> - <div className="thread-info"> - <span className="thread-host">~{params.host}</span> - <span className="thread-separator">•</span> - <span className="thread-id">#{params.id}</span> - </div> - </div> - - <div id="feed-proper"> - <Composer /> - <div id="thread-head"> - <Post poast={toFlat(data.ok)} /> - </div> - <div id="thread-children"> - <ChildTree node={data.ok} /> - </div> - </div> - </main> - ); + else return <ErrorPage msg="weird" />; } -function ChildTree({ node }: { node: FullNode }) { - const { threadChildren, replies } = extractThread(node); - return ( - <> - <div id="tail"> - {threadChildren.map((n) => { - return <Post key={n.id} poast={toFlat(n)} />; - })} - </div> - <div id="replies"> - {replies.map((n) => ( - <ReplyThread key={n.id} node={n} /> - ))} - </div> - </> - ); +export function NostrThreadLoader() { + const params = useParams<{ id: string }>(); + const { id } = params; + if (!id) return <ErrorPage msg="No thread id passed" />; + const dec = decodeNostrKey(id); + if (!dec) return <ErrorPage msg="Unknown thread id format" />; + return <NostrThread id={dec} host="" />; } - -function ReplyThread({ node }: { node: FullNode }) { - // const { threadChildren, replies } = extractThread(node); - const { replies } = extractThread(node); - return ( - <div className="trill-reply-thread"> - <div className="head"> - <Post poast={toFlat(node)} /> - </div> - <div className="tail"> - {replies.map((r) => ( - <Post key={r.id} poast={toFlat(r)} /> - ))} - </div> - </div> - ); -} - -// function OwnData(props: Props) { -// const { api } = useLocalState((s) => ({ -// api: s.api, -// })); -// const { host, id } = props; -// async function fetchThread() { -// return await api!.scryThread(host, id); -// } -// const { isLoading, isError, data, refetch } = useQuery({ -// queryKey: ["trill-thread", host, id], -// queryFn: fetchThread, -// }); -// return isLoading ? ( -// <div className={props.className}> -// <div className="x-center not-found"> -// <p className="x-center">Scrying Post, please wait...</p> -// <img src={spinner} className="x-center s-100" alt="" /> -// </div> -// </div> -// ) : null; -// } -// function SomeoneElses(props: Props) { -// // const { api, following } = useLocalState((s) => ({ -// // api: s.api, -// // following: s.following, -// // })); -// return <div>ho</div>; -// } diff --git a/gui/src/pages/User.tsx b/gui/src/pages/User.tsx index 1611037..80fff05 100644 --- a/gui/src/pages/User.tsx +++ b/gui/src/pages/User.tsx @@ -1,18 +1,12 @@ -// import spinner from "@/assets/icons/spinner.svg"; -import Composer from "@/components/composer/Composer"; -import PostList from "@/components/feed/PostList"; import Profile from "@/components/profile/Profile"; import useLocalState, { useStore } from "@/state/state"; -import Icon from "@/components/Icon"; -import toast from "react-hot-toast"; -import { useEffect, useState } from "react"; -import type { FC } from "@/types/trill"; +import { useState } from "react"; import type { UserType } from "@/types/nostrill"; import { isValidPatp } from "urbit-ob"; import { ErrorPage } from "@/pages/Error"; import { useParams } from "wouter"; -import { isValidNostrKey } from "@/logic/nostr"; -import TrillFeed from "@/components/trill/User"; +import { decodeNostrKey } from "@/logic/nostr"; +import TrillFeed, { Inner } from "@/components/trill/User"; import NostrFeed from "@/components/nostr/User"; function UserLoader() { @@ -22,9 +16,12 @@ function UserLoader() { if (!userString) return <ErrorPage msg="no such user" />; else if (isValidPatp(userString)) return <UserFeed user={{ urbit: userString }} userString={userString} />; - else if (isValidNostrKey(userString)) - return <UserFeed user={{ nostr: userString }} userString={userString} />; - else return <ErrorPage msg="no such user" />; + else { + const nostrKey = decodeNostrKey(userString); + if (nostrKey) + return <UserFeed user={{ nostr: nostrKey }} userString={userString} />; + else return <ErrorPage msg="no such user" />; + } } function UserFeed({ @@ -49,9 +46,8 @@ function UserFeed({ : false; // auto updating on SSE doesn't work if we do shallow const { following } = useStore(); - const feed = following.get(userString); - const hasFeed = !feed ? false : Object.entries(feed).length > 0; - const refetch = () => feed; + const userString2 = "urbit" in user ? user.urbit : user.nostr; + const feed = following.get(userString2); const [isFollowLoading, setIsFollowLoading] = useState(false); const [isAccessLoading, setIsAccessLoading] = useState(false); @@ -60,11 +56,10 @@ function UserFeed({ <div id="user-page"> <Profile user={user} userString={userString} isMe={isMe} /> {isMe ? ( - <MyFeed /> + <MyFeed our={api!.airlock.our!} /> ) : "urbit" in user ? ( <TrillFeed - user={user} - userString={userString} + patp={user.urbit} feed={feed} isFollowLoading={isFollowLoading} setIsFollowLoading={setIsFollowLoading} @@ -73,7 +68,7 @@ function UserFeed({ /> ) : "nostr" in user ? ( <NostrFeed - user={user} + pubkey={user.nostr} userString={userString} feed={feed} isFollowLoading={isFollowLoading} @@ -88,6 +83,9 @@ function UserFeed({ export default UserLoader; -function MyFeed() { - return <></>; +function MyFeed({ our }: { our: string }) { + const following = useLocalState((s) => s.following); + const feed = following.get(our); + if (!feed) return <ErrorPage msg="Critical error" />; + return <Inner feed={feed} refetch={() => {}} />; } |
