From 525af6fa03ed7deb3bc5922708accb5f18b7e379 Mon Sep 17 00:00:00 2001 From: DIYgod Date: Sat, 17 Sep 2022 00:23:57 +0100 Subject: [PATCH] feat: support json feed --- src/components/common/SEOHead.tsx | 6 +++ src/components/icons/RSS3Icon.tsx | 30 +++++++++++++++ src/components/site/SiteHeader.tsx | 8 +++- src/components/ui/UniLink.tsx | 2 +- src/pages/_site/[site]/feed.tsx | 61 ++++++++++++++++++++++++++++++ src/queries/page.server.ts | 18 +++++++++ src/queries/site.server.ts | 16 ++++++++ 7 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 src/components/icons/RSS3Icon.tsx create mode 100644 src/pages/_site/[site]/feed.tsx diff --git a/src/components/common/SEOHead.tsx b/src/components/common/SEOHead.tsx index b35853ee..d024aa5e 100644 --- a/src/components/common/SEOHead.tsx +++ b/src/components/common/SEOHead.tsx @@ -22,6 +22,12 @@ export const SEOHead: React.FC<{ )} + ) } diff --git a/src/components/icons/RSS3Icon.tsx b/src/components/icons/RSS3Icon.tsx new file mode 100644 index 00000000..6bcf3785 --- /dev/null +++ b/src/components/icons/RSS3Icon.tsx @@ -0,0 +1,30 @@ +import React from "react" + +export const RSS3Icon: React.FC> = ( + props, +) => { + return ( + + + + + + + + + + + + + + + + + ) +} diff --git a/src/components/site/SiteHeader.tsx b/src/components/site/SiteHeader.tsx index 6cca1c6c..43a4fa8e 100644 --- a/src/components/site/SiteHeader.tsx +++ b/src/components/site/SiteHeader.tsx @@ -19,6 +19,7 @@ import { } from "~/queries/site" import { useConnectModal } from "@rainbow-me/rainbowkit" import { BlockchainIcon } from "~/components/icons/BlockchainIcon" +import { RSS3Icon } from "~/components/icons/RSS3Icon" import { DotsHorizontalIcon, RssIcon } from "@heroicons/react/solid" import type { Link } from "unidata.js" import { getSiteSubscriptions } from "~/models/site.model" @@ -146,7 +147,7 @@ export const SiteHeader: React.FC<{ }, { text: "View on RSS3", - icon: , + icon: , url: `https://rss3.io/result?search=${site?.metadata?.owner}`, }, { @@ -154,6 +155,11 @@ export const SiteHeader: React.FC<{ icon: , url: `${CSB_SCAN}/address/${site?.metadata?.owner}/transactions`, }, + { + text: "JSON Feed", + icon: , + url: `/feed`, + }, ] const [siteSubscriptionList, setSiteSubscriptionList] = useState([]) diff --git a/src/components/ui/UniLink.tsx b/src/components/ui/UniLink.tsx index 1ab03034..6cdccda0 100644 --- a/src/components/ui/UniLink.tsx +++ b/src/components/ui/UniLink.tsx @@ -18,7 +18,7 @@ export const UniLink: React.FC<{ return {children} } - const isExternal = href && /^https?:\/\//.test(href) + const isExternal = href && (/^https?:\/\//.test(href) || href === "/feed") if (isExternal) { return ( diff --git a/src/pages/_site/[site]/feed.tsx b/src/pages/_site/[site]/feed.tsx new file mode 100644 index 00000000..66e084e4 --- /dev/null +++ b/src/pages/_site/[site]/feed.tsx @@ -0,0 +1,61 @@ +import { GetServerSideProps } from "next" +import { SiteHome } from "~/components/site/SiteHome" +import { SiteLayout } from "~/components/site/SiteLayout" +import { queryClientServer } from "~/lib/query-client.server" +import { fetchGetSite } from "~/queries/site.server" +import { useGetSite } from "~/queries/site" +import { dehydrate, QueryClient } from "@tanstack/react-query" +import { useGetPagesBySite } from "~/queries/page" +import { fetchGetPagesBySite } from "~/queries/page.server" +import { PageVisibilityEnum } from "~/lib/types" +import { getSiteLink } from "~/lib/helpers" + +export const getServerSideProps: GetServerSideProps = async (ctx) => { + ctx.res.setHeader("Content-Type", "application/feed+json") + const domainOrSubdomain = ctx.params!.site as string + + const site = await fetchGetSite(domainOrSubdomain) + const pages = await fetchGetPagesBySite({ + site: domainOrSubdomain, + take: 1000, + type: "post", + visibility: PageVisibilityEnum.Published, + render: true, + }) + + const link = getSiteLink({ + subdomain: site.username || "", + }) + ctx.res.write( + JSON.stringify({ + version: "https://jsonfeed.org/version/1.1", + title: site.name, + description: site.description, + icon: site.avatars?.[0], + home_page_url: link, + feed_url: `${link}/feed.json`, + items: pages.list?.map((page) => ({ + id: page.id, + content_html: page.body?.content, + summary: page.summary?.content, + url: `${link}/${page.slug || page.id}`, + image: page.cover, + date_published: page.date_published, + date_modified: page.date_updated, + authors: page.authors?.map((author) => ({ + name: author, + })), + tags: page.tags, + })), + }), + ) + ctx.res.end() + + return { + props: {}, + } +} + +const SiteFeed: React.FC = () => null + +export default SiteFeed diff --git a/src/queries/page.server.ts b/src/queries/page.server.ts index 89d24a55..a8107524 100644 --- a/src/queries/page.server.ts +++ b/src/queries/page.server.ts @@ -34,3 +34,21 @@ export const prefetchGetPagesBySite = async ( }) } } + +export const fetchGetPagesBySite = async ( + input: Parameters[0], +) => { + const key = ["getPagesBySite", input.site, input] + const data: ReturnType | undefined = + queryClientServer.getQueryData(key) + if (!data) { + return await queryClientServer.fetchQuery(key, async () => { + return pageModel.getPagesBySite(input) + }) + } else { + queryClientServer.fetchQuery(key, async () => { + return pageModel.getPagesBySite(input) + }) + return data + } +} diff --git a/src/queries/site.server.ts b/src/queries/site.server.ts index 62a8d7d5..76dc055f 100644 --- a/src/queries/site.server.ts +++ b/src/queries/site.server.ts @@ -14,3 +14,19 @@ export const prefetchGetSite = async (input: string) => { }) } } + +export const fetchGetSite = async (input: string) => { + const key = ["getSite", input] + const data: ReturnType | undefined = + queryClientServer.getQueryData(key) + if (!data) { + return await queryClientServer.fetchQuery(["getSite", input], async () => { + return siteModel.getSite(input) + }) + } else { + queryClientServer.fetchQuery(["getSite", input], async () => { + return siteModel.getSite(input) + }) + return data + } +}