Skip to content

Commit

Permalink
Merge pull request #45 from route06inc/feat/nav-post-component
Browse files Browse the repository at this point in the history
feat: Add NavPrevPost, NavNextPost
  • Loading branch information
junkisai authored Oct 16, 2024
2 parents 90042aa + 42328aa commit 74a7853
Show file tree
Hide file tree
Showing 25 changed files with 417 additions and 32 deletions.
4 changes: 4 additions & 0 deletions frontend/apps/service-site/.storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ const config: StorybookConfig = {
config.resolve.alias = {
...config.resolve.alias,
'@': path.resolve(__dirname, '../src'),
'contentlayer/generated': path.resolve(
__dirname,
'../.contentlayer/generated',
),
}
}
return config
Expand Down
2 changes: 1 addition & 1 deletion frontend/apps/service-site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"dev:css": "tcm src --watch",
"dev:storybook": "storybook dev -h localhost -p 6006 --no-open",
"build": "pnpm gen && next build",
"build:storybook": "storybook build",
"build:storybook": "pnpm gen && storybook build",
"gen": "conc -c auto pnpm:gen:*",
"gen:css": "tcm src",
"gen:contentlayer": "contentlayer2 build",
Expand Down
3 changes: 1 addition & 2 deletions frontend/apps/service-site/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { fallbackLang } from '@/features/i18n'
import { TopPage } from '@/features/top'

export default function Page() {
return <TopPage lang={fallbackLang} />
return <TopPage />
}
2 changes: 1 addition & 1 deletion frontend/apps/service-site/src/app/posts/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ const paramsSchema = object({
export default function Page({ params }: PageProps) {
const { slug } = parse(paramsSchema, params)

return <PostDetailPage lang={fallbackLang} slug={slug} />
return <PostDetailPage slug={slug} />
}
3 changes: 1 addition & 2 deletions frontend/apps/service-site/src/app/posts/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { fallbackLang } from '@/features/i18n'
import { PostListPage } from '@/features/posts'

export default function Page() {
return <PostListPage lang={fallbackLang} />
return <PostListPage />
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import type { Lang } from '@/features/i18n'
import { createPostDetailLink } from '@/features/posts'
import type { Post } from 'contentlayer/generated'
import Image from 'next/image'
import Link from 'next/link'
import styles from './TopCards.module.css'
interface TopCardsProps {
posts: Post[]
lang?: Lang
lang?: Lang | undefined
}

export function TopCards({ posts, lang }: TopCardsProps) {
return (
<div className={styles.topCards}>
{posts.map((post) => (
<Link
href={lang ? `/${lang}/posts/${post.slug}` : `/posts/${post.slug}`}
href={createPostDetailLink({ lang, slug: post.slug })}
key={post.slug}
>
<div className={styles.topCard}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
.wrapper {
display: grid;
grid-auto-flow: row;
gap: var(--spacing-2);
}

.label {
color: var(--global-body-text);
font-family: var(--main-font);
font-size: var(--font-size-2);
transition: color var(--default-hover-animation-duration)
var(--default-timing-function);
}

.wrapper:hover .label {
color: var(--global-foreground);
}

.titleWrapper {
display: grid;
grid-auto-flow: column;
gap: var(--spacing-half);
justify-content: space-between;
}

.icon {
width: 1.25rem;
height: 1.25rem;
color: var(--global-foreground);
transition: color var(--default-hover-animation-duration)
var(--default-timing-function);
}

.wrapper:hover .icon {
color: var(--primary-color);
}

.title {
display: -webkit-box;
overflow: hidden;
color: var(--global-foreground);
text-overflow: ellipsis;
font-family: var(--message-font);
font-size: var(--font-size-7);
line-height: 120%;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
line-clamp: 3;
transition: color var(--default-hover-animation-duration)
var(--default-timing-function);
}

.wrapper:hover .title {
color: var(--primary-color);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { Meta, StoryObj } from '@storybook/react'

import { aPost } from '../../factories'
import { NavNextPost } from './'

const meta = {
component: NavNextPost,
args: {
post: aPost(),
},
} satisfies Meta<typeof NavNextPost>

export default meta
type Story = StoryObj<typeof meta>

export const Default: Story = {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { Lang } from '@/features/i18n'
import type { Post } from 'contentlayer/generated'
import { ChevronRight } from 'lucide-react'
import Link from 'next/link'
import type { FC } from 'react'
import { createPostDetailLink } from '../../utils'
import styles from './NavNextPost.module.css'

type Props = {
lang?: Lang | undefined
post: Post
}

export const NavNextPost: FC<Props> = ({ lang, post }) => {
return (
<Link
href={createPostDetailLink({ lang, slug: post.slug })}
className={styles.wrapper}
>
<span className={styles.label}>Next</span>
<div className={styles.titleWrapper}>
<span className={styles.title}>{post.title}</span>
<ChevronRight className={styles.icon} />
</div>
</Link>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './NavNextPost'
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
.wrapper {
display: grid;
grid-auto-flow: row;
gap: var(--spacing-2);
}

.label {
padding-left: var(--spacing-6);
color: var(--global-body-text);
font-family: var(--main-font);
font-size: var(--font-size-2);
transition: color var(--default-hover-animation-duration)
var(--default-timing-function);
}

.wrapper:hover .label {
color: var(--global-foreground);
}

.titleWrapper {
display: grid;
grid-auto-flow: column;
gap: var(--spacing-half);
justify-content: flex-start;
}

.icon {
width: 1.25rem;
height: 1.25rem;
color: var(--global-foreground);
transition: color var(--default-hover-animation-duration)
var(--default-timing-function);
}

.wrapper:hover .icon {
color: var(--primary-color);
}

.title {
display: -webkit-box;
overflow: hidden;
color: var(--global-foreground);
text-overflow: ellipsis;
font-family: var(--message-font);
font-size: var(--font-size-7);
line-height: 120%;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
line-clamp: 3;
transition: color var(--default-hover-animation-duration)
var(--default-timing-function);
}

.wrapper:hover .title {
color: var(--primary-color);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { Meta, StoryObj } from '@storybook/react'

import { aPost } from '../../factories'
import { NavPreviousPost } from './'

const meta = {
component: NavPreviousPost,
args: {
post: aPost(),
},
} satisfies Meta<typeof NavPreviousPost>

export default meta
type Story = StoryObj<typeof meta>

export const Default: Story = {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { Lang } from '@/features/i18n'
import type { Post } from 'contentlayer/generated'
import { ChevronLeft } from 'lucide-react'
import Link from 'next/link'
import type { FC } from 'react'
import { createPostDetailLink } from '../../utils'
import styles from './NavPreviousPost.module.css'

type Props = {
lang?: Lang | undefined
post: Post
}

export const NavPreviousPost: FC<Props> = ({ lang, post }) => {
return (
<Link
href={createPostDetailLink({ lang, slug: post.slug })}
className={styles.wrapper}
>
<span className={styles.label}>Previous</span>
<div className={styles.titleWrapper}>
<ChevronLeft className={styles.icon} />
<span className={styles.title}>{post.title}</span>
</div>
</Link>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './NavPreviousPost'
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.navPostWrapper {
display: grid;
grid-template-rows: auto auto;
gap: var(--spacing-8);
}

.navPrev {
grid-area: 0 / 2;
}

.navNext {
grid-area: 0 / 2;
}

@media screen and (min-width: 768px) {
.navPostWrapper {
grid-template-columns: 1fr 1fr;
grid-template-rows: none;
gap: var(--spacing-10);
}

.navPrev {
grid-area: 0 / 1;
}

.navNext {
grid-area: 1 / 2;
}
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,48 @@
import type { Lang } from '@/features/i18n'
import { type Lang, fallbackLang } from '@/features/i18n'
import { LinkHeading } from '@/features/posts/components/LinkHeading'
import { PostHero } from '@/features/posts/components/PostHero'
import { MDXContent } from '@/libs/contentlayer'
import { notFound } from 'next/navigation'
import type { FC } from 'react'
import { findPostByLangAndSlug } from '../../utils'
import { findPostByLangAndSlug, getNextPost, getPrevPost } from '../../utils'
import { NavNextPost } from '../NavNextPost'
import { NavPreviousPost } from '../NavPreviousPost'
import { TableOfContents } from '../TableOfContents'
import styles from './PostDetailPage.module.css'

const TOC_TARGET_CLASS_NAME = 'target-toc'

type Props = {
lang: Lang
lang?: Lang
slug: string
}

export const PostDetailPage: FC<Props> = ({ lang, slug }) => {
const post = findPostByLangAndSlug({ lang, slug })
const post = findPostByLangAndSlug({ lang: lang ?? fallbackLang, slug })
if (!post) notFound()

const prevPost = getPrevPost({ lang: lang ?? fallbackLang, targetPost: post })
const nextPost = getNextPost({ lang: lang ?? fallbackLang, targetPost: post })

return (
<article className={TOC_TARGET_CLASS_NAME} style={{ padding: '0 120px' }}>
<PostHero post={post} />
<TableOfContents contentSelector={TOC_TARGET_CLASS_NAME} />
{/* FIXME: Add href props after implementing categories single page */}
<LinkHeading href="/">Categories</LinkHeading>
<MDXContent code={post.body.code} />
<div className={styles.navPostWrapper}>
{prevPost && (
<div className={styles.navPrev}>
<NavPreviousPost lang={lang} post={prevPost} />
</div>
)}
{nextPost && (
<div className={styles.navNext}>
<NavNextPost lang={lang} post={nextPost} />
</div>
)}
</div>
</article>
)
}
Loading

0 comments on commit 74a7853

Please sign in to comment.