Skip to content

Commit

Permalink
feat: preview page base on postMessage
Browse files Browse the repository at this point in the history
  • Loading branch information
Innei committed Jul 27, 2023
1 parent 5f42521 commit 146c108
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 12 deletions.
190 changes: 186 additions & 4 deletions src/app/preview/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,188 @@
import { NormalContainer } from '~/components/layout/container/Normal'
'use client'

// TODO
export default () => {
return <NormalContainer>TODO</NormalContainer>
import { useEffect, useMemo } from 'react'
import Balancer from 'react-wrap-balancer'
import { atom, useAtomValue } from 'jotai'
import type {
NoteModel,
NoteWrappedPayload,
PostModel,
} from '@mx-space/api-client'

import { simpleCamelcaseKeys } from '@mx-space/api-client'

import { previewDataAtom } from '~/atoms/preview'
import { ErrorBoundary } from '~/components/common/ErrorBoundary'
import { Paper } from '~/components/layout/container/Paper'
import { NoteBanner, NoteMetaBar } from '~/components/widgets/note'
import { PostActionAside } from '~/components/widgets/post'
import { ArticleRightAside } from '~/components/widgets/shared/ArticleRightAside'
import { debounce } from '~/lib/_'
import { jotaiStore } from '~/lib/store'
import { isNoteModel, isPageModel, isPostModel } from '~/lib/url-builder'
import {
CurrentNoteDataAtomProvider,
CurrentNoteDataProvider,
} from '~/providers/note/CurrentNoteDataProvider'
import {
CurrentPostDataAtomProvider,
CurrentPostDataProvider,
} from '~/providers/post/CurrentPostDataProvider'
import {
LayoutRightSidePortal,
LayoutRightSideProvider,
} from '~/providers/shared/LayoutRightSideProvider'
import { WrappedElementProvider } from '~/providers/shared/WrappedElementProvider'

import {
IndentArticleContainer,
NoteHeaderDate,
NoteMarkdown,
NoteMarkdownImageRecordProvider,
NoteTitle,
} from '../notes/[id]/pageExtra'
import {
PostMarkdown,
PostMarkdownImageRecordProvider,
PostMetaBarInternal,
} from '../posts/(post-detail)/[category]/[slug]/pageExtra'

export default function PreviewPage() {
useEffect(() => {
const search = location.search
const searchParams = new URLSearchParams(search)

let targinOrigin = searchParams.get('origin')

if (!targinOrigin) {
return
}
targinOrigin = decodeURIComponent(targinOrigin)
window.opener.postMessage('Preview Page Ready', targinOrigin)

window.addEventListener(
'message',
debounce((e) => {
if (e.origin !== targinOrigin) {
return
}

const parsedData = JSON.parse(e.data)

if (parsedData.type === 'preview') {
jotaiStore.set(previewDataAtom, simpleCamelcaseKeys(parsedData.data))
}
}, 100),
)
}, [])

const previewData = useAtomValue(previewDataAtom)

// console.log(previewData)
if (!previewData) {
return null
}

switch (true) {
case isNoteModel(previewData):
return <NotePreview />
case isPostModel(previewData):
return <PostPreview />

case isPageModel(previewData):
return <div>TODO</div>
}

return null
}

const PostPreview = () => {
const data = useAtomValue(previewDataAtom) as PostModel
const overrideAtom = useMemo(() => atom(null as null | PostModel), [])
return (
<div className="container m-auto mt-[120px] max-w-7xl px-2 md:px-6 lg:p-0">
<CurrentPostDataAtomProvider overrideAtom={overrideAtom}>
<CurrentPostDataProvider data={data} />
<div className="relative flex min-h-[120px] grid-cols-[auto,200px] lg:grid">
<article className="prose relative w-full min-w-0">
<header className="mb-8">
<h1 className="text-center">
<Balancer>{data.title}</Balancer>
</h1>

<PostMetaBarInternal className="mb-8 justify-center" />
</header>
<WrappedElementProvider>
<PostMarkdownImageRecordProvider>
<ErrorBoundary>
<PostMarkdown />
</ErrorBoundary>
</PostMarkdownImageRecordProvider>

<LayoutRightSidePortal>
<ArticleRightAside>
<PostActionAside />
</ArticleRightAside>
</LayoutRightSidePortal>
</WrappedElementProvider>
</article>

<LayoutRightSideProvider className="relative hidden lg:block" />
</div>
</CurrentPostDataAtomProvider>
</div>
)
}

const NotePreview = () => {
const data = useAtomValue(previewDataAtom) as NoteModel

const overrideAtom = useMemo(
() => atom(null as null | NoteWrappedPayload),
[],
)
return (
<div className="mx-auto mt-[100px] max-w-[60rem]">
<CurrentNoteDataAtomProvider overrideAtom={overrideAtom}>
<CurrentNoteDataProvider
data={useMemo(() => {
return {
prev: undefined,
next: undefined,
data: {
...data,
images: data.images ?? [],
count: data.count ?? {
read: 0,
like: 0,
},
},
} as NoteWrappedPayload
}, [data])}
/>
<Paper>
<IndentArticleContainer>
<header>
<NoteTitle />
<span className="flex flex-wrap items-center text-[13px] text-neutral-content/60">
<NoteHeaderDate />
<NoteMetaBar />
</span>
<div className="ml-[-1.25em] mr-[-1.25em] mt-8 text-sm lg:ml-[calc(-3em)] lg:mr-[calc(-3em)]">
<NoteBanner />
</div>
</header>

<WrappedElementProvider>
<NoteMarkdownImageRecordProvider>
<ErrorBoundary>
<NoteMarkdown />
</ErrorBoundary>
</NoteMarkdownImageRecordProvider>
</WrappedElementProvider>
</IndentArticleContainer>
</Paper>
</CurrentNoteDataAtomProvider>
</div>
)
}
4 changes: 4 additions & 0 deletions src/atoms/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { atom } from 'jotai'
import type { NoteModel, PostModel } from '@mx-space/api-client'

export const previewDataAtom = atom<PostModel | NoteModel | null>(null)
2 changes: 1 addition & 1 deletion src/components/ui/link-card/LinkCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const LinkCard = (props: LinkCardProps) => {
)
}
const LinkCardImpl: FC<LinkCardProps> = (props) => {
const { id, source = 'self', className } = props
const { id = '', source = 'self', className } = props

const [loading, setLoading] = useState(true)
const [isError, setIsError] = useState(false)
Expand Down
2 changes: 1 addition & 1 deletion src/components/widgets/peek/NotePreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const NotePreview: FC<NotePreviewProps> = (props) => {
})
const overrideAtom = useMemo(
() => atom(null as null | NoteWrappedPayload),
[data],
[],
)
if (isLoading) return <Loading className="w-full" useDefaultLoadingText />
if (!data) return null
Expand Down
2 changes: 1 addition & 1 deletion src/components/widgets/peek/PostPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const PostPreview: FC<PostPreviewProps> = (props) => {
const { data, isLoading } = useQuery({
...queries.post.bySlug(category, slug),
})
const overrideAtom = useMemo(() => atom(null as null | PostModel), [data])
const overrideAtom = useMemo(() => atom(null as null | PostModel), [])
if (isLoading) return <Loading className="w-full" useDefaultLoadingText />
if (!data) return null
return (
Expand Down
6 changes: 3 additions & 3 deletions src/lib/url-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ export function urlBuilder(path = '') {
return new URL(path, getAggregationData()?.url.webUrl)
}

function isPostModel(model: any): model is PostModel {
export function isPostModel(model: any): model is PostModel {
return (
isDefined(model.title) && isDefined(model.slug) && !isDefined(model.order)
)
}

function isPageModel(model: any): model is PageModel {
export function isPageModel(model: any): model is PageModel {
return (
isDefined(model.title) && isDefined(model.slug) && isDefined(model.order)
)
}

function isNoteModel(model: any): model is NoteModel {
export function isNoteModel(model: any): model is NoteModel {
return isDefined(model.title) && isDefined(model.nid)
}

Expand Down
4 changes: 2 additions & 2 deletions src/providers/article/MarkdownImageRecordProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ const MarkdownImageRecordProviderInternal = createContext(atom([] as Image[]))
export const MarkdownImageRecordProvider: Component<{
images: Image[]
}> = ({ children, images }) => {
const atomRef = useRefValue(() => atom([...images] as Image[]))
const atomRef = useRefValue(() => atom(images as Image[]))

useEffect(() => {
jotaiStore.set(atomRef, [...images])
jotaiStore.set(atomRef, images)
}, [images])

return (
Expand Down

1 comment on commit 146c108

@vercel
Copy link

@vercel vercel bot commented on 146c108 Jul 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

shiro – ./

shiro-innei.vercel.app
shiro-git-main-innei.vercel.app
innei.in
springtide.vercel.app

Please sign in to comment.