From b8286c662a03db9fd23b37b3ea26436fce9de624 Mon Sep 17 00:00:00 2001 From: DIYgod Date: Wed, 29 Jun 2022 20:55:50 +0100 Subject: [PATCH] feat: crossbell renovation - support slug --- src/components/site/SiteHome.tsx | 5 +-- src/lib/types.ts | 11 +++++ src/models/page.model.ts | 43 ++++++++++--------- src/pages/_site/[site]/[page].tsx | 7 +++- src/pages/dashboard/[subdomain]/editor.tsx | 49 +++++++++++++++++----- 5 files changed, 82 insertions(+), 33 deletions(-) diff --git a/src/components/site/SiteHome.tsx b/src/components/site/SiteHome.tsx index 4570fa6a..b496d1e2 100644 --- a/src/components/site/SiteHome.tsx +++ b/src/components/site/SiteHome.tsx @@ -1,8 +1,7 @@ import Link from "next/link" import { formatDate } from "~/lib/date" -import { Paginated, type PostOnSiteHome } from "~/lib/types" +import { Paginated, type PostOnSiteHome, Notes } from "~/lib/types" import { EmptyState } from "../ui/EmptyState" -import { Notes } from "unidata.js" export const SiteHome: React.FC<{ posts?: Notes @@ -17,7 +16,7 @@ export const SiteHome: React.FC<{ {posts.list.map((post) => { const excerpt = post.summary?.content return ( - +

{post.title}

diff --git a/src/lib/types.ts b/src/lib/types.ts index a1624086..1714c958 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -1,3 +1,5 @@ +import type { Note as UniNote } from "unidata.js" + export type Site = { id: string name: string @@ -68,3 +70,12 @@ export type SiteNavigationItem = { label: string url: string } + +export type Note = UniNote & { + slug?: string +} + +export type Notes = { + total: number, + list: Note[], +} \ No newline at end of file diff --git a/src/models/page.model.ts b/src/models/page.model.ts index a8a69f68..2eee6380 100644 --- a/src/models/page.model.ts +++ b/src/models/page.model.ts @@ -9,13 +9,12 @@ import { import { type Gate } from "~/lib/gate.server" import { Rendered, renderPageContent } from "~/markdown" import { notFound } from "~/lib/server-side-props" -import { PageVisibilityEnum } from "~/lib/types" +import { PageVisibilityEnum, Notes } from "~/lib/types" import { isUUID } from "~/lib/uuid" import { getSite } from "./site.model" import { stripHTML } from "~/lib/utils" import { sendEmailForNewPost } from "~/lib/mailgun.server" import unidata from "~/lib/unidata" -import { Notes } from "unidata.js" const checkPageSlug = async ({ slug, @@ -57,6 +56,7 @@ export async function createOrUpdatePage( input: { pageId?: string siteId: string + slug?: string title?: string content?: string published?: boolean @@ -86,7 +86,7 @@ export async function createOrUpdatePage( mime_type: 'text/markdown', } }), - tags: [input.isPost ? "post" : "page"], + tags: [input.isPost ? "post" : "page", ...(input.slug ? ["slug:" + input.slug] : [])], }) } @@ -140,7 +140,7 @@ export async function getPagesBySite( const visibility = input.visibility || PageVisibilityEnum.All - let pages = await unidata.notes.get({ + let pages: Notes | null = await unidata.notes.get({ source: 'Crossbell Note', identity: input.site, platform: 'Crossbell', @@ -176,6 +176,7 @@ export async function getPagesBySite( } } } + page.slug = page.tags?.find((tag) => tag.startsWith("slug:"))?.replace(/^slug:/, "") || page.id return page })) } @@ -197,7 +198,8 @@ export async function deletePage({ site, id }: { site: string, id: string }) { export async function getPage( input: { /** page slug or id, `site` is needed when `page` is a slug */ - page: string + page?: string + pageId?: string site?: string render?: TRender includeAuthors?: boolean @@ -207,30 +209,32 @@ export async function getPage( throw notFound(`site not found`) } - const isPageUUID = isUUID(input.page) - if (!isPageUUID && !input.site) { - throw new Error("input.site is required because input.page is a slug") - } - - const pages = await unidata.notes.get({ + const pages: Notes | null = await unidata.notes.get({ source: 'Crossbell Note', identity: input.site, platform: 'Crossbell', - filter: { - id: input.page, - } + limit: 1000, + ...(input.pageId && { + filter: { + id: input.pageId, + } + }) }) - const page = pages?.list[0] + let page; + if (input.page) { + page = pages?.list.find((item) => { + item.slug = item.tags?.find((tag) => tag.startsWith("slug:"))?.replace(/^slug:/, "") || item.id + return item.slug === input.page + }) + } else { + page = pages?.list[0] + } if (!page) { throw notFound(`page ${input.page} not found`) } - if (new Date(page.date_published) > new Date()) { - throw notFound() - } - if (pages?.list) { pages.list = await Promise.all(pages?.list.map(async (page) => { if (page.body?.content && page.body?.mime_type === 'text/markdown' && input.render) { @@ -246,6 +250,7 @@ export async function getPage( } } } + page.slug = page.tags?.find((tag) => tag.startsWith("slug:"))?.replace(/^slug:/, "") || page.id return page })) } diff --git a/src/pages/_site/[site]/[page].tsx b/src/pages/_site/[site]/[page].tsx index 68cd67b1..d308be83 100644 --- a/src/pages/_site/[site]/[page].tsx +++ b/src/pages/_site/[site]/[page].tsx @@ -13,6 +13,7 @@ import { getUserSites, getSite } from "~/models/site.model" import { getPage } from "~/models/page.model" import { Profile, Note } from "unidata.js" import { PageVisibilityEnum } from "~/lib/types" +import { notFound } from "~/lib/server-side-props" export const getServerSideProps: GetServerSideProps = serverSidePropsHandler( async (ctx) => { @@ -28,7 +29,11 @@ export const getServerSideProps: GetServerSideProps = serverSidePropsHandler( includeAuthors: true, }), ]) - + + if (new Date(page.date_published) > new Date()) { + throw notFound() + } + return { props: { site, diff --git a/src/pages/dashboard/[subdomain]/editor.tsx b/src/pages/dashboard/[subdomain]/editor.tsx index c342f6aa..fb49555f 100644 --- a/src/pages/dashboard/[subdomain]/editor.tsx +++ b/src/pages/dashboard/[subdomain]/editor.tsx @@ -17,13 +17,12 @@ import { useUploadFile } from "~/hooks/useUploadFile" import { inLocalTimezone } from "~/lib/date" import { getSiteLink } from "~/lib/helpers" import { getPageVisibility } from "~/lib/page-helpers" -import { PageVisibilityEnum } from "~/lib/types" +import { PageVisibilityEnum, Note } from "~/lib/types" import { FieldLabel } from "~/components/ui/FieldLabel" import { Button } from "~/components/ui/Button" import { EmailPostModal } from "~/components/common/EmailPostModal" import { useStore } from "~/lib/store" -import type { Note } from "unidata.js" -import { getPagesBySite, createOrUpdatePage } from "~/models/page.model" +import { getPage, createOrUpdatePage } from "~/models/page.model" const getInputDatetimeValue = (date: Date | string) => { const str = dayjs(date).format() @@ -40,15 +39,12 @@ export default function SubdomainEditor() { let [page, setPage] = useState(undefined) useEffect(() => { - if (subdomain) { - getPagesBySite({ - type: isPost ? "post" : "page", + if (subdomain && pageId) { + getPage({ site: subdomain!, - take: 1000, + pageId: pageId, render: false - }).then((pages) => { - console.log(pages, pageId) - const page = (pages?.list || []).find((p) => p.id === pageId) + }).then((page) => { setPage(page) }) } @@ -70,6 +66,7 @@ export default function SubdomainEditor() { publishedAt: new Date().toISOString(), published: false, excerpt: "", + slug: "", }) const [content, setContent] = useState("") @@ -152,6 +149,7 @@ export default function SubdomainEditor() { publishedAt: page.date_published === new Date('9999-01-01').toISOString() ? new Date().toISOString() : page.date_published, published: page.date_published !== new Date('9999-01-01').toISOString(), excerpt: page.summary?.content || "", + slug: page.slug!, }) }, [page]) @@ -238,6 +236,37 @@ export default function SubdomainEditor() { } will be accesisble from this time`} />
+
+ ) => + updateValue("slug", e.target.value) + } + help={ + <> + {values.slug && ( + <> + This {isPost ? "post" : "page"} will be accessible at{" "} + + {getSiteLink({ subdomain, noProtocol: true })}/ + {values.slug} + + + )} + + } + /> +