render page content based on tokens; ignore rendered content field

This commit is contained in:
tmshv committed 2020-03-19 22:34:28 +03:00
1 parent 32d304b26f
commit bb393becc4
8 files changed
+188 -15

No files matched your search

+35
View File
@@ -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",
+2
View File
@@ -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
View File
@@ -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,
+19
View File
@@ -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))}
/>
))
+1 -7
View File
@@ -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 />
+36
View File
@@ -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
}
-4
View File
@@ -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);
+32
View File
@@ -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