a tool for shared writing and social publishing

added prev next buttons

+124 -3
+6 -1
app/lish/[did]/[publication]/[rkey]/LinearDocumentPage.tsx
··· 25 import { decodeQuotePosition } from "./quotePosition"; 26 import { PollData } from "./fetchPollData"; 27 import { SharedPageProps } from "./PostPages"; 28 29 export function LinearDocumentPage({ 30 blocks, ··· 56 57 const isSubpage = !!pageId; 58 59 return ( 60 <> 61 <PageWrapper ··· 83 did={did} 84 prerenderedCodeBlocks={prerenderedCodeBlocks} 85 /> 86 - 87 <ExpandedInteractions 88 pageId={pageId} 89 showComments={preferences.showComments}
··· 25 import { decodeQuotePosition } from "./quotePosition"; 26 import { PollData } from "./fetchPollData"; 27 import { SharedPageProps } from "./PostPages"; 28 + import { PostPrevNextButtons } from "./PostPrevNextButtons"; 29 30 export function LinearDocumentPage({ 31 blocks, ··· 57 58 const isSubpage = !!pageId; 59 60 + console.log("prev/next?: " + preferences.showPrevNext); 61 + 62 return ( 63 <> 64 <PageWrapper ··· 86 did={did} 87 prerenderedCodeBlocks={prerenderedCodeBlocks} 88 /> 89 + <PostPrevNextButtons 90 + showPrevNext={preferences.showPrevNext && !isSubpage} 91 + /> 92 <ExpandedInteractions 93 pageId={pageId} 94 showComments={preferences.showComments}
+58
app/lish/[did]/[publication]/[rkey]/PostPrevNextButtons.tsx
···
··· 1 + "use client"; 2 + import { PubLeafletDocument } from "lexicons/api"; 3 + import { usePublicationData } from "../dashboard/PublicationSWRProvider"; 4 + import { getPublicationURL } from "app/lish/createPub/getPublicationURL"; 5 + import { AtUri } from "@atproto/api"; 6 + import { useParams } from "next/navigation"; 7 + import { getPostPageData } from "./getPostPageData"; 8 + import { PostPageContext } from "./PostPageContext"; 9 + import { useContext } from "react"; 10 + import { SpeedyLink } from "components/SpeedyLink"; 11 + import { ArrowRightTiny } from "components/Icons/ArrowRightTiny"; 12 + 13 + export const PostPrevNextButtons = (props: { 14 + showPrevNext: boolean | undefined; 15 + }) => { 16 + let postData = useContext(PostPageContext); 17 + let pub = postData?.documents_in_publications[0]?.publications; 18 + 19 + if (!props.showPrevNext || !pub || !postData) return; 20 + 21 + function getPostLink(uri: string) { 22 + return pub && uri 23 + ? `${getPublicationURL(pub)}/${new AtUri(uri).rkey}` 24 + : "leaflet.pub/not-found"; 25 + } 26 + let prevPost = postData?.prevNext?.prev; 27 + let nextPost = postData?.prevNext?.next; 28 + 29 + return ( 30 + <div className="flex flex-col gap-1 w-full px-3 sm:px-4 pb-2 pt-2"> 31 + {/*<hr className="border-border-light" />*/} 32 + <div className="flex justify-between w-full gap-8 "> 33 + {nextPost ? ( 34 + <SpeedyLink 35 + href={getPostLink(nextPost.uri)} 36 + className="flex gap-1 items-center truncate min-w-0 basis-1/2" 37 + > 38 + <ArrowRightTiny className="rotate-180 shrink-0" /> 39 + <div className="min-w-0 truncate">{nextPost.title}</div> 40 + </SpeedyLink> 41 + ) : ( 42 + <div /> 43 + )} 44 + {prevPost ? ( 45 + <SpeedyLink 46 + href={getPostLink(prevPost.uri)} 47 + className="flex gap-1 items-center truncate min-w-0 basis-1/2 justify-end" 48 + > 49 + <div className="min-w-0 truncate">{prevPost.title}</div> 50 + <ArrowRightTiny className="shrink-0" /> 51 + </SpeedyLink> 52 + ) : ( 53 + <div /> 54 + )} 55 + </div> 56 + </div> 57 + ); 58 + };
+58 -1
app/lish/[did]/[publication]/[rkey]/getPostPageData.ts
··· 10 data, 11 uri, 12 comments_on_documents(*, bsky_profiles(*)), 13 - documents_in_publications(publications(*, publication_subscriptions(*))), 14 document_mentions_in_bsky(*), 15 leaflets_in_publications(*) 16 `, ··· 51 ?.record as PubLeafletPublication.Record 52 )?.theme || (document?.data as PubLeafletDocument.Record)?.theme; 53 54 return { 55 ...document, 56 quotesAndMentions, 57 theme, 58 }; 59 } 60
··· 10 data, 11 uri, 12 comments_on_documents(*, bsky_profiles(*)), 13 + documents_in_publications(publications(*, 14 + documents_in_publications(documents(uri, data)), 15 + publication_subscriptions(*)) 16 + ), 17 document_mentions_in_bsky(*), 18 leaflets_in_publications(*) 19 `, ··· 54 ?.record as PubLeafletPublication.Record 55 )?.theme || (document?.data as PubLeafletDocument.Record)?.theme; 56 57 + // Calculate prev/next documents from the fetched publication documents 58 + let prevNext: 59 + | { 60 + prev?: { uri: string; title: string }; 61 + next?: { uri: string; title: string }; 62 + } 63 + | undefined; 64 + 65 + const currentPublishedAt = (document.data as PubLeafletDocument.Record) 66 + ?.publishedAt; 67 + const allDocs = 68 + document.documents_in_publications[0]?.publications 69 + ?.documents_in_publications; 70 + 71 + if (currentPublishedAt && allDocs) { 72 + // Filter and sort documents by publishedAt 73 + const sortedDocs = allDocs 74 + .map((dip) => ({ 75 + uri: dip?.documents?.uri, 76 + title: (dip?.documents?.data as PubLeafletDocument.Record).title, 77 + publishedAt: (dip?.documents?.data as PubLeafletDocument.Record) 78 + .publishedAt, 79 + })) 80 + .filter((doc) => doc.publishedAt) // Only include docs with publishedAt 81 + .sort( 82 + (a, b) => 83 + new Date(a.publishedAt!).getTime() - 84 + new Date(b.publishedAt!).getTime(), 85 + ); 86 + 87 + // Find current document index 88 + const currentIndex = sortedDocs.findIndex((doc) => doc.uri === uri); 89 + 90 + if (currentIndex !== -1) { 91 + prevNext = { 92 + prev: 93 + currentIndex > 0 94 + ? { 95 + uri: sortedDocs[currentIndex - 1].uri || "", 96 + title: sortedDocs[currentIndex - 1].title, 97 + } 98 + : undefined, 99 + next: 100 + currentIndex < sortedDocs.length - 1 101 + ? { 102 + uri: sortedDocs[currentIndex + 1].uri || "", 103 + title: sortedDocs[currentIndex + 1].title, 104 + } 105 + : undefined, 106 + }; 107 + } 108 + } 109 + 110 return { 111 ...document, 112 quotesAndMentions, 113 theme, 114 + prevNext, 115 }; 116 } 117
+2 -1
app/lish/[did]/[publication]/dashboard/settings/PostOptions.tsx
··· 53 showPrevNext: showPrevNext, 54 }, 55 }); 56 - toast({ type: "success", content: "Posts Updated!" }); 57 props.setLoading(false); 58 mutate("publication-data"); 59 }}
··· 53 showPrevNext: showPrevNext, 54 }, 55 }); 56 + toast({ type: "success", content: <strong>Posts Updated!</strong> }); 57 + console.log(record.preferences?.showPrevNext); 58 props.setLoading(false); 59 mutate("publication-data"); 60 }}