render page content based on tokens; ignore rendered content field
This commit is contained in:
1 parent
32d304b26f
commit
bb393becc4
8 files changed
+188
-15
No files matched your search
Generated
+35
@@ -4451,6 +4451,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"linkify-it": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
|
||||
"integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
|
||||
"requires": {
|
||||
"uc.micro": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"loader-runner": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz",
|
||||
@@ -4667,6 +4675,18 @@
|
||||
"object-visit": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"markdown-it": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz",
|
||||
"integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==",
|
||||
"requires": {
|
||||
"argparse": "^1.0.7",
|
||||
"entities": "~2.0.0",
|
||||
"linkify-it": "^2.0.0",
|
||||
"mdurl": "^1.0.1",
|
||||
"uc.micro": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"md5.js": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
|
||||
@@ -4684,6 +4704,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"mdurl": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
|
||||
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
|
||||
},
|
||||
"memory-fs": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
|
||||
@@ -8077,6 +8102,16 @@
|
||||
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
|
||||
"dev": true
|
||||
},
|
||||
"typograf": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/typograf/-/typograf-6.11.0.tgz",
|
||||
"integrity": "sha512-7PcX6gyocBoNoCnLNmgqzd7ohp7SrW44U6YIqk91+7x4ivVlzpRltN4JK7mtBov9CVPsfX6W8yXTnoUxImSzwQ=="
|
||||
},
|
||||
"uc.micro": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
|
||||
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
|
||||
},
|
||||
"underscore": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "http://storage.mds.yandex.net/get-npm/35308/underscore-1.8.3.tgz",
|
||||
|
||||
@@ -23,10 +23,12 @@
|
||||
"classnames": "^2.2.6",
|
||||
"date-fns": "^2.11.0",
|
||||
"lodash": "^4.17.15",
|
||||
"markdown-it": "^10.0.0",
|
||||
"next": "^9.3.1",
|
||||
"react": "^16.13.0",
|
||||
"react-dom": "^16.13.0",
|
||||
"sitemap": "^1.5.0",
|
||||
"typograf": "^6.11.0",
|
||||
"use-media": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
+63
-4
@@ -2,11 +2,13 @@ import Head from 'next/head'
|
||||
import { App } from 'src/components/App'
|
||||
import { tail } from 'lodash'
|
||||
import { Page } from 'src/components/Page'
|
||||
import { Markdown } from 'src/components/Markdown'
|
||||
import { Meta } from 'src/components/Meta'
|
||||
import { MetaBuilder } from 'src/lib/meta'
|
||||
import { createApiUrl, requestGet, IResponseItems } from 'src/next-lib'
|
||||
import { NextPage } from 'next'
|
||||
import { IBreadcumbsPart, IMeta, IPage, ITag } from 'src/types'
|
||||
import { IBreadcumbsPart, IMeta, IPage, ITag, FileTokenData, Token } from 'src/types'
|
||||
import { joinTokens } from 'src/lib/tokens'
|
||||
|
||||
function array<T>(value: T | T[]) {
|
||||
return Array.isArray(value)
|
||||
@@ -14,13 +16,33 @@ function array<T>(value: T | T[]) {
|
||||
: [value]
|
||||
}
|
||||
|
||||
const File: React.SFC<FileTokenData> = props => (
|
||||
<div className="document-row">
|
||||
<a href={props['url']} className="invisible">
|
||||
<div className="document-row__image">
|
||||
<img src={props['image_url']} alt={props['title']} />
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<div className="document-row__file">
|
||||
<a href={props['url']}>{props['title']}</a>
|
||||
</div>
|
||||
|
||||
<div className="document-row__file-info">
|
||||
<a href="document['file_url']" target="_blank">
|
||||
{props.file_format} ({props.file_size})
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
type Props = {
|
||||
title: string
|
||||
tags: ITag[]
|
||||
date: string
|
||||
content: string
|
||||
breadcrumb: IBreadcumbsPart[]
|
||||
meta?: IMeta
|
||||
tokens?: Token[]
|
||||
}
|
||||
|
||||
const Index: NextPage<Props> = props => (
|
||||
@@ -42,7 +64,43 @@ const Index: NextPage<Props> = props => (
|
||||
tags={props.tags}
|
||||
date={props.date ? new Date(props.date) : null}
|
||||
>
|
||||
{props.content}
|
||||
<article className={'article'}>
|
||||
{joinTokens(props.tokens ?? []).map((x, i) => {
|
||||
switch (x.token) {
|
||||
case 'text':
|
||||
return (
|
||||
<Markdown
|
||||
data={x.data}
|
||||
/>
|
||||
)
|
||||
|
||||
case 'image':
|
||||
return (
|
||||
<div className="kazimir__image">
|
||||
<figure>
|
||||
<img
|
||||
src={x.data.src}
|
||||
alt={x.data.alt}
|
||||
/>
|
||||
<figcaption>{x.data.caption}</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
)
|
||||
|
||||
case 'file':
|
||||
return (
|
||||
<File {...x.data} />
|
||||
)
|
||||
|
||||
default:
|
||||
return (
|
||||
<pre>
|
||||
{JSON.stringify(x)}
|
||||
</pre>
|
||||
)
|
||||
}
|
||||
})}
|
||||
</article>
|
||||
</Page>
|
||||
</App>
|
||||
)
|
||||
@@ -66,10 +124,11 @@ export const getStaticProps = async (ctx: any) => {
|
||||
.setTitle(page.title)
|
||||
.setDescription(description)
|
||||
.build()
|
||||
const tokens = page.tokens
|
||||
|
||||
return {
|
||||
props: {
|
||||
content: page.data,
|
||||
tokens,
|
||||
title: page.title,
|
||||
tags: page.tags,
|
||||
date: page.date,
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Html } from 'src/components/Html'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
import Typograf from 'typograf'
|
||||
import { memo } from 'react'
|
||||
|
||||
const tp = new Typograf({ locale: ['ru'] })
|
||||
const md = new MarkdownIt({
|
||||
html: true,
|
||||
})
|
||||
|
||||
export type MarkdownProps = {
|
||||
data: string
|
||||
}
|
||||
|
||||
export const Markdown: React.SFC<MarkdownProps> = memo(props => (
|
||||
<Html
|
||||
html={tp.execute(md.render(props.data))}
|
||||
/>
|
||||
))
|
||||
@@ -7,19 +7,13 @@ import { ITag } from 'src/types'
|
||||
|
||||
export type PageProps = {
|
||||
style?: React.CSSProperties
|
||||
children: string
|
||||
date: Date
|
||||
tags: ITag[]
|
||||
}
|
||||
|
||||
export const Page: React.FC<PageProps> = props => (
|
||||
<div className={'page'} style={props.style}>
|
||||
<Html
|
||||
as={'article'}
|
||||
className={'article'}
|
||||
html={props.children}
|
||||
/>
|
||||
|
||||
{props.children}
|
||||
<hr />
|
||||
<Share />
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { TextToken, Token } from 'src/types'
|
||||
|
||||
export function joinTextTokens(tokens: TextToken[]): TextToken {
|
||||
return {
|
||||
token: 'text',
|
||||
data: tokens
|
||||
.map(x => x.data)
|
||||
.join('\n\n'),
|
||||
}
|
||||
}
|
||||
|
||||
export function joinTokens(tokens: Token[]): Token[] {
|
||||
let buffer: TextToken[] = []
|
||||
const result: Token[] = []
|
||||
|
||||
for (const token of tokens) {
|
||||
if (token.token === 'text') {
|
||||
buffer.push(token)
|
||||
continue
|
||||
}
|
||||
|
||||
const compiledToken = joinTextTokens(buffer)
|
||||
buffer = []
|
||||
|
||||
result.push(compiledToken)
|
||||
result.push(token)
|
||||
}
|
||||
|
||||
if (buffer.length) {
|
||||
result.push(
|
||||
joinTextTokens(buffer)
|
||||
)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -27,10 +27,6 @@
|
||||
line-height: var(--article-line-height);
|
||||
}
|
||||
|
||||
.article p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.article blockquote {
|
||||
padding: var(--size-m);
|
||||
font-size: var(--font-size-accent);
|
||||
|
||||
@@ -103,3 +103,35 @@ export type ImageDefinition = {
|
||||
height: number
|
||||
src: string
|
||||
}
|
||||
|
||||
export type TextToken = {
|
||||
token: 'text'
|
||||
data: string
|
||||
}
|
||||
|
||||
export type ImageToken = {
|
||||
token: 'image'
|
||||
data: {
|
||||
src: string
|
||||
alt: string
|
||||
caption: string
|
||||
}
|
||||
}
|
||||
|
||||
export type FileTokenData = {
|
||||
url: string
|
||||
slug: string
|
||||
image_url: string
|
||||
file_url: string
|
||||
title: string
|
||||
file_size: number
|
||||
file_format: 'application/pdf'
|
||||
}
|
||||
|
||||
export type FileToken = {
|
||||
token: 'file'
|
||||
data: FileTokenData
|
||||
}
|
||||
|
||||
export type Token = TextToken | ImageToken | FileToken
|
||||
|
||||
Reference in new issue
Block a user