Skip to content

Commit

Permalink
feat: post detail page
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <i@innei.in>
  • Loading branch information
Innei committed Jun 21, 2023
1 parent 90877db commit 456b9d5
Show file tree
Hide file tree
Showing 30 changed files with 376 additions and 95 deletions.
2 changes: 2 additions & 0 deletions src/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export const appConfig = {
process.env.NODE_ENV === 'production'
? 'https://innei.ren'
: 'http://localhost:2323',

favicon: 'https://cdn.innei.ren/github_innei.svg',
},

module: {
Expand Down
9 changes: 8 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { headers } from 'next/dist/client/components/headers'

import { ClerkProvider } from '@clerk/nextjs'

import { appConfig } from '~/app.config'
import { Root } from '~/components/layout/root/Root'
import { REQUEST_GEO, REQUEST_PATHNAME } from '~/constants/system'
import { defineMetadata } from '~/lib/define-metadata'
Expand All @@ -30,6 +31,8 @@ export const generateMetadata = defineMetadata(async (_, getData) => {
},
description: seo.description,
keywords: seo.keywords?.join(',') || '',
icons: [appConfig.site.favicon],

themeColor: [
{ media: '(prefers-color-scheme: dark)', color: '#000212' },
{ media: '(prefers-color-scheme: light)', color: '#fafafa' },
Expand All @@ -56,6 +59,10 @@ export const generateMetadata = defineMetadata(async (_, getData) => {
locale: 'zh_CN',
type: 'website',
url: url.webUrl,
images: {
url: user.avatar,
username: user.name,
},
},
twitter: {
creator: `@${user.username}`,
Expand Down Expand Up @@ -108,7 +115,7 @@ export default async function RootLayout(props: Props) {
<ClerkProvider>
<html lang="zh-CN" className="noise" suppressHydrationWarning>
<body
className={`${sansFont.variable} ${serifFont.variable} m-0 h-full p-0 font-sans antialiased`}
className={`${sansFont.variable} ${serifFont.variable} m-0 h-full p-0 font-sans`}
>
<Providers>
<Hydrate state={dehydratedState}>
Expand Down
15 changes: 8 additions & 7 deletions src/app/notes/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type { MarkdownToJSX } from '~/components/ui/markdown'
import { ClientOnly } from '~/components/common/ClientOnly'
import { PageDataHolder } from '~/components/common/PageHolder'
import { MdiClockOutline } from '~/components/icons/clock'
import { useSetHeaderMetaInfo } from '~/components/layout/header/internal/hooks'
import { useSetHeaderMetaInfo } from '~/components/layout/header/hooks'
import { FloatPopover } from '~/components/ui/float-popover'
import { Loading } from '~/components/ui/loading'
import { Markdown } from '~/components/ui/markdown'
Expand All @@ -22,7 +22,8 @@ import { NoteTopic } from '~/components/widgets/note/NoteTopic'
import { SubscribeBell } from '~/components/widgets/subscribe/SubscribeBell'
import { TocAside, TocAutoScroll } from '~/components/widgets/toc'
import { XLogInfoForNote, XLogSummaryForNote } from '~/components/widgets/xlog'
import { useNoteByNidQuery, useNoteData } from '~/hooks/data/use-note'
import { useCurrentNoteData, useNoteByNidQuery } from '~/hooks/data/use-note'
import { noopArr } from '~/lib/noop'
import { MarkdownImageRecordProvider } from '~/providers/article/MarkdownImageRecordProvider'
import {
CurrentNoteIdProvider,
Expand All @@ -39,8 +40,6 @@ import { NoteHideIfSecret } from '../../../components/widgets/note/NoteHideIfSec
import { NoteMetaBar } from '../../../components/widgets/note/NoteMetaBar'
import styles from './page.module.css'

const noopArr = [] as Image[]

const PageImpl = () => {
const { id } = useParams() as { id: string }
const { data } = useNoteByNidQuery(id)
Expand Down Expand Up @@ -108,7 +107,9 @@ const NotePage = memo(({ note }: { note: NoteModel }) => {
<NoteHideIfSecret>
<XLogSummaryForNote />
<WrappedElementProvider>
<MarkdownImageRecordProvider images={note.images || noopArr}>
<MarkdownImageRecordProvider
images={note.images || (noopArr as Image[])}
>
<Markdown
as="main"
renderers={MarkdownRenderers}
Expand Down Expand Up @@ -139,7 +140,7 @@ const NotePage = memo(({ note }: { note: NoteModel }) => {
})

const NoteTitle = () => {
const note = useNoteData()
const note = useCurrentNoteData()
if (!note) return null
const title = note.title
return (
Expand All @@ -150,7 +151,7 @@ const NoteTitle = () => {
}

const NoteDateMeta = () => {
const note = useNoteData()
const note = useCurrentNoteData()
if (!note) return null

const dateFormat = dayjs(note.created)
Expand Down
2 changes: 1 addition & 1 deletion src/app/posts/(post-detail)/Container.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const Container: Component = ({ children }) => {
return (
<div className="container m-auto mt-12 max-w-7xl px-2 md:p-0">
<div className="container m-auto mt-[120px] max-w-7xl px-2 md:p-0">
{children}
</div>
)
Expand Down
3 changes: 3 additions & 0 deletions src/app/posts/(post-detail)/[category]/[slug]/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Loading } from '~/components/ui/loading'

export default () => <Loading useDefaultLoadingText />
86 changes: 85 additions & 1 deletion src/app/posts/(post-detail)/[category]/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,88 @@
'use client'

import { useEffect } from 'react'
import { Balancer } from 'react-wrap-balancer'
import type { Image, PostModel } from '@mx-space/api-client'

import { ReadIndicator } from '~/components/common/ReadIndicator'
import { useSetHeaderMetaInfo } from '~/components/layout/header/hooks'
import { Loading } from '~/components/ui/loading'
import { Markdown } from '~/components/ui/markdown'
import { PostActionAside } from '~/components/widgets/post/PostActionAside'
import { PostMetaBar } from '~/components/widgets/post/PostMetaBar'
import { SubscribeBell } from '~/components/widgets/subscribe/SubscribeBell'
import { TocAside, TocAutoScroll } from '~/components/widgets/toc'
import { XLogInfoForPost, XLogSummaryForPost } from '~/components/widgets/xlog'
import { useCurrentPostData } from '~/hooks/data/use-post'
import { noopArr } from '~/lib/noop'
import { MarkdownImageRecordProvider } from '~/providers/article/MarkdownImageRecordProvider'
import { LayoutRightSidePortal } from '~/providers/shared/LayoutRightSideProvider'
import { WrappedElementProvider } from '~/providers/shared/WrappedElementProvider'

const useHeaderMeta = (data?: PostModel | null) => {
const setHeader = useSetHeaderMetaInfo()
useEffect(() => {
if (!data) return
setHeader({
title: data.title,
description:
data.category.name +
(data.tags.length > 0 ? ` / ${data.tags.join(', ')}` : ''),
slug: `${data.category.slug}/${data.slug}`,
})
}, [
data?.title,
data?.category.name,
data?.tags.length,
data?.category.slug,
data?.slug,
])
}
export default () => {
return <div>Test</div>
const data = useCurrentPostData()

useHeaderMeta(data)
if (!data) {
return <Loading useDefaultLoadingText />
}

return (
<div>
<article className="prose">
<header className="mb-8">
<h1>
<Balancer>{data.title}</Balancer>
</h1>
<div>
<PostMetaBar data={data} />
</div>

<XLogSummaryForPost />
</header>
<WrappedElementProvider>
<MarkdownImageRecordProvider
images={data.images || (noopArr as Image[])}
>
<main className="relative">
<Markdown value={data.text} />
</main>
</MarkdownImageRecordProvider>

<LayoutRightSidePortal>
<TocAside
className="sticky top-[120px] ml-4 mt-[120px]"
treeClassName="max-h-[calc(100vh-6rem-4.5rem-300px)] h-[calc(100vh-6rem-4.5rem-300px)] min-h-[120px] relative"
accessory={ReadIndicator}
>
<PostActionAside className="translate-y-full" />
</TocAside>
<TocAutoScroll />
</LayoutRightSidePortal>
</WrappedElementProvider>
</article>

<SubscribeBell defaultType="post_c" />
<XLogInfoForPost />
</div>
)
}
7 changes: 6 additions & 1 deletion src/components/layout/header/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import { useEffect } from 'react'

import { useSetHeaderShouldShowBg } from '~/components/layout/header/internal/hooks'
import {
useSetHeaderMetaInfo,
useSetHeaderShouldShowBg,
} from '~/components/layout/header/internal/hooks'

export const useHideHeaderBgInRoute = () => {
const setter = useSetHeaderShouldShowBg()
Expand All @@ -18,3 +21,5 @@ export const HeaderHideBg = () => {
useHideHeaderBgInRoute()
return null
}

export { useSetHeaderMetaInfo }
9 changes: 6 additions & 3 deletions src/components/layout/header/internal/HeaderMeta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,12 @@ export const HeaderMeta = () => {
</h2>
</div>

<div className="hidden min-w-0 flex-shrink-0 flex-col text-right leading-5 lg:flex">
<span className="whitespace-pre text-base-content"> {slug}</span>
<span className="font-medium text-gray-400 dark:text-gray-600">
<div className="hidden min-w-0 flex-shrink flex-col text-right leading-5 lg:flex">
<span className="min-w-0 truncate whitespace-pre text-gray-600/60 dark:text-gray-300/60">
{' '}
{slug}
</span>
<span className="font-medium text-gray-600 dark:text-gray-300">
{seoTitle}
</span>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
position: relative;

pre > code {
background-color: var(--light-bg) !important;
@apply block bg-base-100 font-mono text-[14px] font-medium;
}
}

Expand Down
13 changes: 8 additions & 5 deletions src/components/ui/image/ZoomedImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ export const ImageLazy: Component<TImageProps & BaseImageProps> = ({
const [zoomer_] = useState(() => {
if (isServer) return null
if (zoomer) return zoomer
const zoom = mediumZoom(undefined, {
background: 'var(--sbg)',
})
const zoom = mediumZoom(undefined)
zoomer = zoom
return zoom
}) as [Zoom]
Expand Down Expand Up @@ -180,8 +178,8 @@ const Placeholder: FC<

if (containerWidth <= 0) return
const { height: scaleHeight, width: scaleWidth } = calculateDimensions({
width: nextHeight,
height: nextWidth,
width: nextWidth,
height: nextHeight,
max: {
width: containerWidth,
height: Infinity,
Expand All @@ -199,6 +197,11 @@ const Placeholder: FC<
return (
<span
className={styles.base}
data-width={scaledSize.scaleWidth}
data-height={scaledSize.scaleHeight}
data-from-record-height={imageMeta?.height}
data-from-record-width={imageMeta?.width}
data-src={src}
style={{
height: scaledSize.scaleHeight,
width: scaledSize.scaleWidth,
Expand Down
4 changes: 4 additions & 0 deletions src/components/ui/markdown/markdown.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,8 @@
input[type='checkbox']:read-only {
@apply cursor-not-allowed;
}

code {
@apply font-mono;
}
}
6 changes: 3 additions & 3 deletions src/components/ui/markdown/renderers/link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ const ExtendIcon = () => (
className="inline align-middle leading-normal"
>
<path
fill="var(--shizuku-text-color)"
fill="currentColor"
d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"
/>
<polygon
fill="var(--shizuku-text-color)"
fill="currentColor"
points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"
/>
</svg>
Expand Down Expand Up @@ -84,7 +84,7 @@ export const MLink: FC<{
{props.children}
</a>

{ExtendIcon}
<ExtendIcon />
</>
),
[handleRedirect, props.children, props.href, props.title],
Expand Down
6 changes: 3 additions & 3 deletions src/components/widgets/note/NoteActionAside.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { NoteWrappedPayload } from '@mx-space/api-client'

import { MotionButtonBase } from '~/components/ui/button'
import { useIsClient } from '~/hooks/common/use-is-client'
import { useNoteData } from '~/hooks/data/use-note'
import { useCurrentNoteData } from '~/hooks/data/use-note'
import { routeBuilder, Routes } from '~/lib/route-builder'
import { toast } from '~/lib/toast'
import { urlBuilder } from '~/lib/url-builder'
Expand Down Expand Up @@ -35,7 +35,7 @@ export const NoteActionAside: Component = ({ className }) => {
}

const LikeButton = () => {
const note = useNoteData()
const note = useCurrentNoteData()

const queryClient = useQueryClient()
const control = useAnimationControls()
Expand Down Expand Up @@ -112,7 +112,7 @@ const LikeButton = () => {
const ShareButton = () => {
const hasShare = 'share' in navigator
const isClient = useIsClient()
const note = useNoteData()
const note = useCurrentNoteData()
const aggregation = useAggregationData()
if (!isClient) return null
if (!note) return null
Expand Down
4 changes: 2 additions & 2 deletions src/components/widgets/note/NoteHideIfSecret.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import { useEffect, useMemo } from 'react'
import dayjs from 'dayjs'

import { useIsLogged } from '~/atoms/owner'
import { useNoteData } from '~/hooks/data/use-note'
import { useCurrentNoteData } from '~/hooks/data/use-note'
import { toast } from '~/lib/toast'

export const NoteHideIfSecret: Component = ({ children }) => {
const note = useNoteData()
const note = useCurrentNoteData()
const secretDate = useMemo(() => new Date(note?.secret!), [note?.secret])
const isSecret = note?.secret
? dayjs(note?.secret).isAfter(new Date())
Expand Down
4 changes: 2 additions & 2 deletions src/components/widgets/note/NoteMetaBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import type { ReactNode } from 'react'

import { CreativeCommonsIcon } from '~/components/icons/cc'
import { DividerVertical } from '~/components/ui/divider'
import { useNoteData } from '~/hooks/data/use-note'
import { useCurrentNoteData } from '~/hooks/data/use-note'
import { mood2icon, weather2icon } from '~/lib/meta-icon'

const dividerVertical = <DividerVertical className="!mx-2 scale-y-50" />
const dividerVerticalWithKey = () =>
cloneElement(dividerVertical, { key: `divider-${Math.random()}` })
const sectionBlockClassName = 'flex items-center space-x-1 flex-shrink-0'
export const NoteMetaBar = () => {
const note = useNoteData()
const note = useCurrentNoteData()
if (!note) return null

const children = [] as ReactNode[]
Expand Down
4 changes: 2 additions & 2 deletions src/components/widgets/note/NoteTimeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import Link from 'next/link'
import { tv } from 'tailwind-variants'

import { LeftToRightTransitionView } from '~/components/ui/transition/LeftToRightTransitionView'
import { useNoteData } from '~/hooks/data/use-note'
import { useCurrentNoteData } from '~/hooks/data/use-note'
import { routeBuilder, Routes } from '~/lib/route-builder'
import { clsxm } from '~/utils/helper'
import { apiClient } from '~/utils/request'

export const NoteTimeline = () => {
const note = useNoteData()
const note = useCurrentNoteData()
const noteId = note?.id

const { data: timelineData } = useQuery(
Expand Down
Loading

1 comment on commit 456b9d5

@vercel
Copy link

@vercel vercel bot commented on 456b9d5 Jun 21, 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:

springtide – ./

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

Please sign in to comment.