feat: new window preview

This commit is contained in:
DIYgod 2022-10-21 00:23:15 +01:00
parent 5d450474a5
commit 0230701042
No known key found for this signature in database
GPG Key ID: D159328F47A80DCA
6 changed files with 148 additions and 68 deletions

View File

@ -8,7 +8,13 @@ export const SitePage: React.FC<{
}> = ({ page }) => {
return (
<>
<div className="">
{page?.preview && (
<div className="fixed top-0 left-0 w-full text-center text-orange-500 bg-gray-100 py-2 opacity-80 text-sm">
Currently in private preview mode, the content is different from the
public
</div>
)}
<div>
{page?.tags?.includes("post") ? (
<h2 className="xlog-post-title text-4xl font-bold">{page.title}</h2>
) : (
@ -23,7 +29,7 @@ export const SitePage: React.FC<{
content={page?.body?.content}
toc={true}
></PageContent>
<PostFooter page={page} />
{page?.metadata && <PostFooter page={page} />}
</>
)
}

View File

@ -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
}

View File

@ -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 = {

View File

@ -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<TRender extends boolean = false>(
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
}

View File

@ -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 <SitePage page={page.data} />
}
SitePagePage.getLayout = (page: ReactElement) => {
return <SiteLayout>{page}</SiteLayout>
}
export default SitePagePage

View File

@ -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<string>("")
@ -353,25 +350,37 @@ export default function SubdomainEditor() {
<div className="flex items-center space-x-3">
<span
className={clsx(
`text-sm`,
published ? `text-accent` : `text-zinc-300`,
`text-sm capitalize`,
visibility === PageVisibilityEnum.Draft
? `text-zinc-300`
: visibility === PageVisibilityEnum.Modified
? "text-orange-600"
: "text-green-600",
)}
>
{visibility === PageVisibilityEnum.Published
? `Published${
getStorage(draftKey)
? " and local modifications exist"
: ""
}`
: visibility === PageVisibilityEnum.Scheduled
? "Scheduled"
: "Draft"}
{visibility.toLowerCase()}
</span>
<Button
isAutoWidth
onClick={() => {
window.open(
`/_site/${subdomain}/preview/${draftKey.replace(
`draft-${subdomain}-`,
"",
)}`,
)
}}
>
Preview
</Button>
<PublishButton
save={savePage}
published={published}
published={visibility !== PageVisibilityEnum.Draft}
isSaving={createOrUpdatePage.isLoading}
isDisabled={published && !getStorage(draftKey) ? true : false}
isDisabled={
visibility !== PageVisibilityEnum.Modified &&
visibility !== PageVisibilityEnum.Draft
}
/>
</div>
</header>