tangled
alpha
login
or
join now
leaflet.pub
/
leaflet
289
fork
atom
a tool for shared writing and social publishing
289
fork
atom
overview
issues
28
pulls
pipelines
added prev next buttons
cozylittle.house
2 months ago
645c26e1
74ba8bf0
+124
-3
4 changed files
expand all
collapse all
unified
split
app
lish
[did]
[publication]
[rkey]
LinearDocumentPage.tsx
PostPrevNextButtons.tsx
getPostPageData.ts
dashboard
settings
PostOptions.tsx
+6
-1
app/lish/[did]/[publication]/[rkey]/LinearDocumentPage.tsx
···
25
import { decodeQuotePosition } from "./quotePosition";
26
import { PollData } from "./fetchPollData";
27
import { SharedPageProps } from "./PostPages";
0
28
29
export function LinearDocumentPage({
30
blocks,
···
56
57
const isSubpage = !!pageId;
58
0
0
59
return (
60
<>
61
<PageWrapper
···
83
did={did}
84
prerenderedCodeBlocks={prerenderedCodeBlocks}
85
/>
86
-
0
0
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
···
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
···
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(*))),
0
0
0
14
document_mentions_in_bsky(*),
15
leaflets_in_publications(*)
16
`,
···
51
?.record as PubLeafletPublication.Record
52
)?.theme || (document?.data as PubLeafletDocument.Record)?.theme;
53
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
54
return {
55
...document,
56
quotesAndMentions,
57
theme,
0
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!" });
0
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
}}