diff --git a/bun.lockb b/bun.lockb index 6656860..118717e 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 093f7c3..7d03859 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "axios": "^1.7.9", "axios-case-converter": "^1.1.1", "cookies-next": "^5.0.2", + "feed": "^4.2.2", "next": "15.1.3", "next-nprogress-bar": "^2.4.3", "react": "^19.0.0", diff --git a/src/pages/posts/feed.ts b/src/pages/posts/feed.ts new file mode 100644 index 0000000..f4ca772 --- /dev/null +++ b/src/pages/posts/feed.ts @@ -0,0 +1,72 @@ +import { sni } from '@/services/network' +import { SnPost } from '@/services/post' +import { GetServerSideProps } from 'next' +import { Feed } from 'feed' + +function generateFeed(posts: SnPost[]): string { + const feed = new Feed({ + title: 'Solar Network Posts', + description: 'All posts on the Solar Network platform, and now you can view them via the RSS feed!', + id: 'https://solsynth.dev/posts', + link: 'https://solsynth.dev/posts', + favicon: 'https://solsynth.dev/favicon.png', + copyright: `All rights reserved ${new Date().getFullYear()} © Solsynth LLC & Post Publishers`, + updated: new Date(posts[0].createdAt), + generator: 'Capital', + feedLinks: { + json: 'https://example.com/json', + atom: 'https://example.com/atom', + }, + }) + + for (const p of posts) { + feed.addItem({ + id: p.id.toString(), + title: p.body.title ?? `Post #${p.id}`, + description: p.body.description, + link: + p.alias && p.aliasPrefix + ? `https://solsynth.dev/posts/${p.aliasPrefix}/${p.alias}` + : `https://solsynth.dev/posts/${p.id}`, + content: p.body.content, + date: new Date(p.publishedAt ?? p.createdAt), + published: new Date(p.publishedAt ?? p.createdAt), + copyright: `All right reserved ${new Date().getFullYear()} © @${p.publisher.name}`, + author: [ + { + name: `@${p.publisher.name}`, + }, + ], + }) + } + + return feed.rss2() +} + +export const getServerSideProps: GetServerSideProps = async ({ res, query }) => { + let page: number = parseInt(query.page as string) + if (isNaN(page)) page = 1 + + const countPerPage = 20 + + const { data: resp } = await sni.get<{ data: SnPost[] }>('/cgi/co/posts', { + params: { + take: countPerPage, + offset: (page - 1) * countPerPage, + }, + }) + + const sitemap = generateFeed(resp.data) + + res.setHeader('Content-Type', 'text/xml') + res.write(sitemap) + res.end() + + return { + props: {}, + } +} + +export default function PostSiteMap() { + // getServerSideProps will do the heavy lifting +} diff --git a/src/pages/posts/index.tsx b/src/pages/posts/index.tsx index ade03b3..32f3295 100644 --- a/src/pages/posts/index.tsx +++ b/src/pages/posts/index.tsx @@ -2,9 +2,20 @@ import { AttachmentItem } from '@/components/attachments/AttachmentItem' import { SnAttachment, listAttachment } from '@/services/attachment' import { getAttachmentUrl, sni } from '@/services/network' import { SnPost } from '@/services/post' -import { Avatar, Box, Container, Divider, Grid2 as Grid, Pagination, Paper, Typography } from '@mui/material' +import { + Avatar, + Box, + Button, + Container, + Divider, + Grid2 as Grid, + Link, + Pagination, + Paper, + Typography, +} from '@mui/material' import { GetServerSideProps, InferGetServerSidePropsType } from 'next' -import Link from 'next/link' +import NextLink from 'next/link' import { useRouter } from 'next/router' import rehypeSanitize from 'rehype-sanitize' import rehypeStringify from 'rehype-stringify' @@ -86,7 +97,7 @@ export default function PostList({ posts, page, pages }: InferGetServerSideProps - + {(p.body.title || p.body.content) && ( @@ -108,7 +119,7 @@ export default function PostList({ posts, page, pages }: InferGetServerSideProps {p.body.content &&
} - + {p.attachments && ( ))} - router.push('/posts?page=' + page)} - /> + + router.push('/posts?page=' + page)} /> + + RSS Feed + + ) }