diff options
| author | Armand Philippot <git@armandphilippot.com> | 2022-01-13 18:35:48 +0100 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2022-01-13 18:35:48 +0100 |
| commit | 02ee023272c4f28fd866de40dd2b15a7f7b75a4a (patch) | |
| tree | e7d29b73e679f07906068593d0e25bf6f8c728fe /src | |
| parent | 606461f857e06b06429dd5738be642f9d1b459be (diff) | |
| parent | 320b5782f348d42f6a2bb74a70d4d114525355e4 (diff) | |
feat: add feeds (rss, atom, json)
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/Layouts/Layout.tsx | 22 | ||||
| -rw-r--r-- | src/pages/atom.xml.tsx | 20 | ||||
| -rw-r--r-- | src/pages/feed.json.tsx | 20 | ||||
| -rw-r--r-- | src/pages/feed.xml.tsx | 20 | ||||
| -rw-r--r-- | src/utils/helpers/rss.ts | 61 |
5 files changed, 143 insertions, 0 deletions
diff --git a/src/components/Layouts/Layout.tsx b/src/components/Layouts/Layout.tsx index 35e7d27..8a57cf6 100644 --- a/src/components/Layouts/Layout.tsx +++ b/src/components/Layouts/Layout.tsx @@ -4,6 +4,8 @@ import Header from '@components/Header/Header'; import Main from '@components/Main/Main'; import Breadcrumb from '@components/Breadcrumb/Breadcrumb'; import { t } from '@lingui/macro'; +import Head from 'next/head'; +import { config } from '@config/website'; const Layout = ({ children, @@ -14,6 +16,26 @@ const Layout = ({ }) => { return ( <> + <Head> + <link + rel="alternate" + href="/feed.xml" + type="application/rss+xml" + title={`${config.name}'s RSS feed`} + /> + <link + rel="alternate" + href="/atom.xml" + type="application/atom+xml" + title={`${config.name}'s RSS feed`} + /> + <link + rel="alternate" + href="/feed.json" + type="application/feed+json" + title={`${config.name}'s RSS feed`} + /> + </Head> <a href="#main" className="screen-reader-text">{t`Skip to content`}</a> <Header isHome={isHome} /> <Main>{children}</Main> diff --git a/src/pages/atom.xml.tsx b/src/pages/atom.xml.tsx new file mode 100644 index 0000000..e6908bd --- /dev/null +++ b/src/pages/atom.xml.tsx @@ -0,0 +1,20 @@ +import { generateFeed } from '@utils/helpers/rss'; +import { GetServerSideProps } from 'next'; + +const Feed = () => null; + +export const getServerSideProps: GetServerSideProps = async ({ res }) => { + const feed = await generateFeed(); + + if (res) { + res.setHeader('Content-Type', 'text/xml'); + res.write(`${feed.atom1()}`); + res.end(); + } + + return { + props: {}, + }; +}; + +export default Feed; diff --git a/src/pages/feed.json.tsx b/src/pages/feed.json.tsx new file mode 100644 index 0000000..e113b46 --- /dev/null +++ b/src/pages/feed.json.tsx @@ -0,0 +1,20 @@ +import { generateFeed } from '@utils/helpers/rss'; +import { GetServerSideProps } from 'next'; + +const Feed = () => null; + +export const getServerSideProps: GetServerSideProps = async ({ res }) => { + const feed = await generateFeed(); + + if (res) { + res.setHeader('Content-Type', 'application/json'); + res.write(`${feed.json1()}`); + res.end(); + } + + return { + props: {}, + }; +}; + +export default Feed; diff --git a/src/pages/feed.xml.tsx b/src/pages/feed.xml.tsx new file mode 100644 index 0000000..093cab8 --- /dev/null +++ b/src/pages/feed.xml.tsx @@ -0,0 +1,20 @@ +import { generateFeed } from '@utils/helpers/rss'; +import { GetServerSideProps } from 'next'; + +const Feed = () => null; + +export const getServerSideProps: GetServerSideProps = async ({ res }) => { + const feed = await generateFeed(); + + if (res) { + res.setHeader('Content-Type', 'text/xml'); + res.write(`${feed.rss2()}`); + res.end(); + } + + return { + props: {}, + }; +}; + +export default Feed; diff --git a/src/utils/helpers/rss.ts b/src/utils/helpers/rss.ts new file mode 100644 index 0000000..7851ff8 --- /dev/null +++ b/src/utils/helpers/rss.ts @@ -0,0 +1,61 @@ +import { config } from '@config/website'; +import { getPublishedPosts } from '@services/graphql/queries'; +import { ArticlePreview } from '@ts/types/articles'; +import { PostsList } from '@ts/types/blog'; +import { Feed } from 'feed'; + +const getAllPosts = async (): Promise<ArticlePreview[]> => { + const posts: ArticlePreview[] = []; + let hasNextPage = true; + let after = undefined; + + do { + const postsList: PostsList = await getPublishedPosts({ first: 10, after }); + posts.push(...postsList.posts); + hasNextPage = postsList.pageInfo.hasNextPage; + after = postsList.pageInfo.endCursor; + } while (hasNextPage); + + return posts; +}; + +export const generateFeed = async () => { + const websiteUrl = process.env.FRONTEND_URL ? process.env.FRONTEND_URL : ''; + const author = { + name: config.name, + email: process.env.AUTHOR_EMAIL, + link: websiteUrl, + }; + const copyright = `${config.name} CC BY SA ${config.copyright.startYear} - ${config.copyright.endYear}`; + const title = `${config.name} | ${config.baseline}`; + + const feed = new Feed({ + author, + copyright, + description: process.env.FEED_DESCRIPTION, + feedLinks: { + json: `${websiteUrl}/feed/json`, + atom: `${websiteUrl}/feed/atom`, + }, + generator: 'Feed & NextJS', + id: websiteUrl, + language: config.defaultLocale, + link: websiteUrl, + title, + }); + + const posts = await getAllPosts(); + + posts.forEach((post) => { + feed.addItem({ + content: post.intro, + date: new Date(post.dates.publication), + description: post.intro, + id: post.id, + link: `${websiteUrl}/article/${post.slug}`, + title: post.title, + }); + }); + + return feed; +}; |
