+ Currently in private preview mode, the content is different from the
+ public
+
{page?.tags?.includes("post") ? (
{page.title}
) : (
@@ -23,7 +29,7 @@ export const SitePage: React.FC<{
content={page?.body?.content}
toc={true}
>
-
+ {page?.metadata &&
}
>
)
}
diff --git a/src/lib/page-helpers.ts b/src/lib/page-helpers.ts
index f16c8253..d87b3df7 100644
--- a/src/lib/page-helpers.ts
+++ b/src/lib/page-helpers.ts
@@ -4,14 +4,20 @@ import { PageVisibilityEnum } from "./types"
export const getPageVisibility = ({
date_published,
metadata,
+ preview,
}: {
date_published?: string
metadata?: Object
+ preview?: boolean
}) => {
if (!metadata) {
return PageVisibilityEnum.Draft
} else if (dayjs(date_published).isBefore(new Date())) {
- return PageVisibilityEnum.Published
+ if (preview) {
+ return PageVisibilityEnum.Modified
+ } else {
+ return PageVisibilityEnum.Published
+ }
} else {
return PageVisibilityEnum.Scheduled
}
diff --git a/src/lib/types.ts b/src/lib/types.ts
index 0254f0a3..cb97bbd3 100644
--- a/src/lib/types.ts
+++ b/src/lib/types.ts
@@ -26,6 +26,7 @@ export enum PageVisibilityEnum {
Scheduled = "scheduled",
Draft = "draft",
Crossbell = "crossbell",
+ Modified = "published and modified",
}
export type PostOnSiteHome = {
@@ -83,6 +84,7 @@ export type Note = UniNote & {
mime_type?: string
element?: ReactElement
}
+ preview?: boolean
}
export type Notes = {
diff --git a/src/models/page.model.ts b/src/models/page.model.ts
index 467b486e..4187131d 100644
--- a/src/models/page.model.ts
+++ b/src/models/page.model.ts
@@ -130,7 +130,7 @@ const expandPage = (page: Note, render: boolean) => {
const getLocalPages = (input: { site: string; isPost?: boolean }) => {
const pages: Note[] = []
- getKeys(`draft-${input.site}-local`).forEach((key) => {
+ getKeys(`draft-${input.site}`).forEach((key) => {
const page = getStorage(key)
if (input.isPost === undefined || page.isPost === input.isPost) {
pages.push({
@@ -140,6 +140,7 @@ const getLocalPages = (input: { site: string; isPost?: boolean }) => {
content: page.values?.content,
mime_type: "text/markdown",
},
+ date_updated: new Date(page.date).toISOString(),
date_published: page.values?.publishedAt,
summary: {
content: page.values?.excerpt,
@@ -161,6 +162,7 @@ const getLocalPages = (input: { site: string; isPost?: boolean }) => {
},
],
}),
+ preview: true,
})
}
})
@@ -225,8 +227,20 @@ export async function getPagesBySite(
site: input.site,
isPost: input.type === "post",
})
- pages.list = pages.list.concat(local)
- pages.total += local.length
+ local.forEach((localPage) => {
+ const index = pages.list.findIndex((page) => page.id === localPage.id)
+ if (
+ index >= 0 &&
+ new Date(localPage.date_updated) >
+ new Date(pages.list[index].date_updated)
+ ) {
+ localPage.metadata = pages.list[index].metadata
+ pages.list[index] = localPage
+ } else {
+ pages.list.push(localPage)
+ pages.total++
+ }
+ })
}
if (pages?.list) {
@@ -285,43 +299,60 @@ export async function getPage
(
const local = getLocalPages({
site: input.site,
})
- const localPage = local.find((page) => page.id === input.pageId)
+ const localPage = local.find(
+ (page) => page.id === input.page || page.id === input.pageId,
+ )
+
+ const mustLocal = input.pageId?.startsWith("local-")
+
+ const pages: Notes | null = mustLocal
+ ? null
+ : await (customUnidata || unidata).notes.get({
+ source: "Crossbell Note",
+ identity: input.site,
+ platform: "Crossbell",
+ limit: 1000,
+ ...(input.pageId && {
+ filter: {
+ id: input.pageId,
+ },
+ }),
+ })
let page
- if (localPage) {
- page = localPage
- } else {
- const pages: Notes | null = await (customUnidata || unidata).notes.get({
- source: "Crossbell Note",
- identity: input.site,
- platform: "Crossbell",
- limit: 1000,
- ...(input.pageId && {
- filter: {
- id: input.pageId,
- },
- }),
+ if (input.page) {
+ page = pages?.list.find((item) => {
+ item.slug =
+ item.attributes?.find((a) => a.trait_type === "xlog_slug")?.value ||
+ item.metadata?.raw?._xlog_slug ||
+ item.metadata?.raw?._crosslog_slug ||
+ item.id
+ return item.slug === input.page || item.id === input.page
})
+ } else {
+ page = pages?.list[0]
+ }
- if (input.page) {
- page = pages?.list.find((item) => {
- item.slug =
- item.attributes?.find((a) => a.trait_type === "xlog_slug")?.value ||
- item.metadata?.raw?._xlog_slug ||
- item.metadata?.raw?._crosslog_slug ||
- item.id
- return item.slug === input.page || item.id === input.page
- })
+ if (localPage) {
+ if (page) {
+ if (new Date(localPage.date_updated) > new Date(page.date_updated)) {
+ localPage.metadata = page.metadata
+ page = localPage
+ }
} else {
- page = pages?.list[0]
+ page = localPage
}
}
- if (!page) {
+ if (!page && !mustLocal) {
throw notFound(`page ${input.page} not found`)
}
- expandPage(page, input.render || false)
+ if (page) {
+ expandPage(page, input.render || false)
+ } else {
+ page = null
+ }
return page
}
diff --git a/src/pages/_site/[site]/preview/[page].tsx b/src/pages/_site/[site]/preview/[page].tsx
new file mode 100644
index 00000000..54e35656
--- /dev/null
+++ b/src/pages/_site/[site]/preview/[page].tsx
@@ -0,0 +1,26 @@
+import { SiteLayout } from "~/components/site/SiteLayout"
+import { SitePage } from "~/components/site/SitePage"
+import { useGetPage } from "~/queries/page"
+import type { ReactElement } from "react"
+import { useRouter } from "next/router"
+
+function SitePagePage() {
+ const router = useRouter()
+ const site = router.query.site as string
+ const pageSlug = router.query.page as string
+
+ const page = useGetPage({
+ site: site,
+ page: pageSlug,
+ render: true,
+ includeAuthors: true,
+ })
+
+ return
+}
+
+SitePagePage.getLayout = (page: ReactElement) => {
+ return {page}
+}
+
+export default SitePagePage
diff --git a/src/pages/dashboard/[subdomain]/editor.tsx b/src/pages/dashboard/[subdomain]/editor.tsx
index 4f902a19..18b4b07d 100644
--- a/src/pages/dashboard/[subdomain]/editor.tsx
+++ b/src/pages/dashboard/[subdomain]/editor.tsx
@@ -24,7 +24,7 @@ import { getPageVisibility } from "~/lib/page-helpers"
import { PageVisibilityEnum } from "~/lib/types"
import { useGetPage, useCreateOrUpdatePage } from "~/queries/page"
import { useGetSite } from "~/queries/site"
-import { getStorage, setStorage, delStorage } from "~/lib/storage"
+import { setStorage, delStorage } from "~/lib/storage"
import { nanoid } from "nanoid"
import { useQueryClient } from "@tanstack/react-query"
import { PageContent } from "~/components/common/PageContent"
@@ -34,6 +34,7 @@ import type { Root } from "hast"
import type { EditorView } from "@codemirror/view"
import { Editor } from "~/components/ui/Editor"
import { renderPageContent } from "~/markdown"
+import { Button } from "~/components/ui/Button"
const getInputDatetimeValue = (date: Date | string) => {
const str = dayjs(date).format()
@@ -52,9 +53,13 @@ export default function SubdomainEditor() {
useEffect(() => {
if (subdomain) {
if (!pageId) {
- const key = `draft-${subdomain}-local-${nanoid()}`
+ const randomId = nanoid()
+ const key = `draft-${subdomain}-local-${randomId}`
setDraftKey(key)
queryClient.invalidateQueries(["getPagesBySite", subdomain])
+ router.replace(
+ `/dashboard/${subdomain}/editor?id=local-${randomId}&type=${router.query.type}`,
+ )
} else {
setDraftKey(`draft-${subdomain}-${pageId}`)
}
@@ -65,14 +70,13 @@ export default function SubdomainEditor() {
const page = useGetPage({
site: subdomain!,
- pageId: pageId,
+ pageId: pageId || draftKey.replace(`draft-${subdomain}-`, ""),
render: false,
})
const visibility = page.data
? getPageVisibility(page.data)
: PageVisibilityEnum.Draft
- const published = visibility !== PageVisibilityEnum.Draft
const uploadFile = useUploadFile()
@@ -161,25 +165,18 @@ export default function SubdomainEditor() {
useEffect(() => {
if (!page.data || !draftKey) return
- const local = getStorage(draftKey)
- const useLocal =
- local?.date && +new Date(local?.date) > +new Date(page.data.date_updated)
- if (useLocal && local?.values) {
- setValues(local?.values)
- } else {
- setValues({
- title: page.data.title || "",
- publishedAt: page.data.date_published,
- published: !!page.data.id,
- excerpt: page.data.summary?.content || "",
- slug: page.data.slug || "",
- tags:
- page.data.tags
- ?.filter((tag) => tag !== "post" && tag !== "page")
- ?.join(", ") || "",
- content: page.data.body?.content || "",
- })
- }
+ setValues({
+ title: page.data.title || "",
+ publishedAt: page.data.date_published,
+ published: !!page.data.id,
+ excerpt: page.data.summary?.content || "",
+ slug: page.data.slug || "",
+ tags:
+ page.data.tags
+ ?.filter((tag) => tag !== "post" && tag !== "page")
+ ?.join(", ") || "",
+ content: page.data.body?.content || "",
+ })
}, [page.data, subdomain, draftKey])
const [currentScrollArea, setCurrentScrollArea] = useState("")
@@ -353,25 +350,37 @@ export default function SubdomainEditor() {
- {visibility === PageVisibilityEnum.Published
- ? `Published${
- getStorage(draftKey)
- ? " and local modifications exist"
- : ""
- }`
- : visibility === PageVisibilityEnum.Scheduled
- ? "Scheduled"
- : "Draft"}
+ {visibility.toLowerCase()}
+