-
Notifications
You must be signed in to change notification settings - Fork 185
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2cc6f7e
commit 2611650
Showing
39 changed files
with
777 additions
and
87 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { SimpleGrid } from '@vkontakte/vkui'; | ||
import { useRouter } from 'next/router'; | ||
import { useConfig } from '../contexts'; | ||
import { Post } from './components/Post'; | ||
import { findPosts } from './helpers'; | ||
import { getTags } from './tags'; | ||
|
||
export function PostsLayout() { | ||
const config = useConfig(); | ||
const { pageMap, frontMatter } = config; | ||
const posts = findPosts(pageMap); | ||
const router = useRouter(); | ||
const { type } = frontMatter; | ||
const tagName = type === 'tag' ? router.query.tag : null; | ||
|
||
return ( | ||
<SimpleGrid columns={3} gap="xl"> | ||
{posts.map((post) => { | ||
const tags = getTags(post.frontMatter); | ||
if (tagName) { | ||
if (!Array.isArray(tagName) && !tags.includes(tagName)) { | ||
return null; | ||
} | ||
} else if (type === 'tag') { | ||
return null; | ||
} | ||
|
||
const postTitle = post.frontMatter?.title || post.name; | ||
const date: Date | null = post.frontMatter?.date ? new Date(post.frontMatter.date) : null; | ||
|
||
return ( | ||
<Post | ||
key={post.route} | ||
title={postTitle} | ||
description={post.frontMatter?.description} | ||
publishDate={date} | ||
tags={tags} | ||
route={post.route} | ||
image={post.frontMatter?.image} | ||
/> | ||
); | ||
})} | ||
</SimpleGrid> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import * as React from 'react'; | ||
import { Title } from '@vkontakte/vkui'; | ||
|
||
export interface HeadingProps extends React.ComponentProps<'h2'> { | ||
Tag?: `h${1 | 2 | 3}`; | ||
} | ||
|
||
export function Heading({ Tag = 'h2', children, ...props }: HeadingProps) { | ||
return ( | ||
<Title Component={Tag} {...props}> | ||
{children} | ||
</Title> | ||
); | ||
} |
40 changes: 40 additions & 0 deletions
40
packages/vkui-docs-theme/src/blog/components/Post/Post.module.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
.root { | ||
display: flex; | ||
flex-direction: column; | ||
overflow: hidden; | ||
} | ||
|
||
.heading { | ||
--vkui--color_text_link: var(--vkui--color_text_primary); | ||
|
||
color: var(--vkui--color_text_primary); | ||
} | ||
|
||
.headingPrimary { | ||
font-size: 40px; | ||
line-height: 46px; | ||
} | ||
|
||
.date:not(:only-child)::after { | ||
content: '•'; | ||
padding-inline: var(--vkui--spacing_size_s); | ||
} | ||
|
||
.content { | ||
padding-block: var(--vkui--size_base_padding_vertical--regular); | ||
padding-inline: var(--vkui--size_base_padding_horizontal--regular); | ||
display: flex; | ||
flex-direction: column; | ||
flex-grow: 1; | ||
|
||
--vkui--color_text_link: var(--vkui--color_text_primary); | ||
} | ||
|
||
.description { | ||
margin-block-start: var(--vkui--spacing_size_s); | ||
} | ||
|
||
.meta { | ||
margin-block-start: auto; | ||
padding-block-start: var(--vkui--spacing_size_s); | ||
} |
40 changes: 40 additions & 0 deletions
40
packages/vkui-docs-theme/src/blog/components/Post/Post.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import * as React from 'react'; | ||
import { Card, Link, Text } from '@vkontakte/vkui'; | ||
import NextLink from 'next/link'; | ||
import { useRouter } from 'next/router'; | ||
import { PostHeading } from './PostHeading'; | ||
import { PostMeta, type PostMetaProps } from './PostMeta'; | ||
import styles from './Post.module.css'; | ||
|
||
interface PostProps extends PostMetaProps { | ||
title: React.ReactNode; | ||
description?: React.ReactNode; | ||
route?: string; | ||
image?: string; | ||
} | ||
|
||
export function Post({ title, description, tags, publishDate, route, image }: PostProps) { | ||
const router = useRouter(); | ||
|
||
return ( | ||
<Card className={styles.root} mode="outline-tint" Component="article"> | ||
<img src={`${router.basePath}${image}`} alt={`Лого для карточки ${title}`} width="100%" /> | ||
<div className={styles.content}> | ||
<PostHeading> | ||
<Link href={route} Component={NextLink}> | ||
{title} | ||
</Link> | ||
</PostHeading> | ||
{description && ( | ||
<Text className={styles.description}> | ||
{description}{' '} | ||
<Link href={route} Component={NextLink}> | ||
Читать далее... | ||
</Link> | ||
</Text> | ||
)} | ||
<PostMeta className={styles.meta} publishDate={publishDate} tags={tags} /> | ||
</div> | ||
</Card> | ||
); | ||
} |
20 changes: 20 additions & 0 deletions
20
packages/vkui-docs-theme/src/blog/components/Post/PostHeading.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import * as React from 'react'; | ||
import { classNames } from '@vkontakte/vkjs'; | ||
import { Heading, type HeadingProps } from '../Heading'; | ||
import styles from './Post.module.css'; | ||
|
||
export interface PostHeadingProps extends HeadingProps { | ||
children?: React.ReactNode; | ||
} | ||
|
||
export function PostHeading({ children, Tag }: PostHeadingProps) { | ||
if (Tag === 'h1') { | ||
return <h1 className={classNames(styles.heading, styles.headingPrimary)}>{children}</h1>; | ||
} | ||
|
||
return ( | ||
<Heading className={styles.heading} Tag={Tag}> | ||
{children} | ||
</Heading> | ||
); | ||
} |
27 changes: 27 additions & 0 deletions
27
packages/vkui-docs-theme/src/blog/components/Post/PostMeta.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { ContentBadge, Footnote } from '@vkontakte/vkui'; | ||
import NextLink from 'next/link'; | ||
import { DateFormatter } from '../../../helpers/date'; | ||
import styles from './Post.module.css'; | ||
|
||
export interface PostMetaProps { | ||
publishDate?: Date | null; | ||
tags?: string[]; | ||
className?: string; | ||
} | ||
|
||
export function PostMeta({ publishDate, tags = [], className }: PostMetaProps) { | ||
return ( | ||
<div className={className}> | ||
{publishDate && ( | ||
<Footnote className={styles.date} inline> | ||
<time dateTime={publishDate.toISOString()}>{DateFormatter.format(publishDate)}</time> | ||
</Footnote> | ||
)} | ||
{tags.map((tag) => ( | ||
<NextLink href={`/blog/tags/${tag}`} key={tag}> | ||
<ContentBadge appearance="neutral"># {tag}</ContentBadge> | ||
</NextLink> | ||
))} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export { Post } from './Post'; | ||
export { PostMeta } from './PostMeta'; | ||
export { PostHeading } from './PostHeading'; |
29 changes: 29 additions & 0 deletions
29
packages/vkui-docs-theme/src/blog/components/PostHeader.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { Icon12ChevronLeft } from '@vkontakte/icons'; | ||
import { Button } from '@vkontakte/vkui'; | ||
import { useRouter } from 'next/router'; | ||
import { useConfig } from '../../contexts'; | ||
import { getTags } from '../tags'; | ||
import { PostHeading, PostMeta } from './Post'; | ||
|
||
export function PostHeader() { | ||
const config = useConfig(); | ||
const { frontMatter } = config; | ||
const router = useRouter(); | ||
const tags = getTags(frontMatter); | ||
|
||
const back = () => { | ||
void router.push('/blog'); | ||
}; | ||
|
||
const date: Date | null = frontMatter.date ? new Date(frontMatter.date) : null; | ||
|
||
return ( | ||
<div> | ||
<Button onClick={back} mode="link" before={<Icon12ChevronLeft />} size="s"> | ||
Назад | ||
</Button> | ||
<PostMeta publishDate={date} tags={tags} /> | ||
<PostHeading Tag="h1">{frontMatter.title}</PostHeading> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import type { MdxFile, PageMapItem, PageOpts } from 'nextra'; | ||
|
||
const sortPosts = (a: MdxFile, b: MdxFile): number => { | ||
if (!a.frontMatter?.date || !b.frontMatter?.date) { | ||
return -1; | ||
} | ||
|
||
return new Date(b.frontMatter.date).getTime() - new Date(a.frontMatter.date).getTime(); | ||
}; | ||
|
||
export const isPost = (page: PageMapItem): page is MdxFile => { | ||
if ('frontMatter' in page) { | ||
const { draft, type } = page.frontMatter || {}; | ||
return !draft && type === 'post'; | ||
} | ||
return false; | ||
}; | ||
|
||
export function findPosts(pageMap: PageOpts['pageMap']) { | ||
const posts: MdxFile[] = []; | ||
|
||
for (const item of pageMap) { | ||
if ('children' in item && item.name === 'blog') { | ||
for (const pageMapItem of item.children) { | ||
if (isPost(pageMapItem)) { | ||
posts.push(pageMapItem); | ||
} | ||
} | ||
} | ||
} | ||
posts.sort(sortPosts); | ||
return posts; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { PostsLayout } from './PostsLayout'; | ||
export { PostHeader } from './components/PostHeader'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import type { GetStaticPaths } from 'next'; | ||
import Head from 'next/head'; | ||
import type { FrontMatter, PageMapItem } from 'nextra'; | ||
import { useData } from 'nextra/hooks'; | ||
import { isPost } from './helpers'; | ||
|
||
const NEXTRA_INTERNAL = Symbol.for('__nextra_internal__'); | ||
|
||
export const TagTitle = () => { | ||
const { tag } = useData(); | ||
const title = `Посты по теме ${tag}`; | ||
return ( | ||
<Head> | ||
<title>{title}</title> | ||
</Head> | ||
); | ||
}; | ||
|
||
export const TagName = () => { | ||
const { tag } = useData(); | ||
return tag || null; | ||
}; | ||
|
||
export function getTags(frontMatter: FrontMatter | undefined) { | ||
if (!frontMatter) { | ||
return []; | ||
} | ||
const tags: string | string[] = frontMatter.tag || []; | ||
return (Array.isArray(tags) ? tags : tags.split(',')).map((s) => s.trim()); | ||
} | ||
|
||
const getStaticTags = (pageMap: PageMapItem[]) => { | ||
const tags = []; | ||
|
||
for (const item of pageMap) { | ||
if ('children' in item && item.name === 'blog') { | ||
for (const pageMapItem of item.children) { | ||
if (isPost(pageMapItem)) { | ||
tags.push(...getTags(pageMapItem.frontMatter)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
return [...new Set(tags)]; | ||
}; | ||
|
||
export const getStaticPathsTags: GetStaticPaths = () => { | ||
const tags = getStaticTags((globalThis as any)[NEXTRA_INTERNAL].pageMap); | ||
return { | ||
paths: tags.map((v: any) => ({ params: { tag: v } })), | ||
fallback: false, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.