Merge branch 'v1.1' into v1.1-lazylaoding
This commit is contained in:
commit
3e5ed14dc6
|
@ -12,7 +12,7 @@ type Props = {
|
|||
export const ArticleImageBlockWrapper = ({ image, order }: Props) => {
|
||||
return (
|
||||
<Container id={`i-${order}`}>
|
||||
<LightBox caption={image.caption || ''}>
|
||||
<LightBox caption={image.captionHTML || ''}>
|
||||
<ResponsiveImage data={image} />
|
||||
</LightBox>
|
||||
</Container>
|
||||
|
|
|
@ -10,10 +10,7 @@ const ArticleFooter = ({ data: post }: { data: LPE.Article.Document }) => {
|
|||
const { data, relatedArticles, articlesFromSameAuthors } = post
|
||||
|
||||
const footnotes = useMemo(() => {
|
||||
return data.content.flatMap((b) =>
|
||||
// @ts-ignore
|
||||
b.type === 'text' ? b.footnotes : [],
|
||||
)
|
||||
return data.content.flatMap((b) => b.footnotes || [])
|
||||
}, [data])
|
||||
|
||||
return (
|
||||
|
|
|
@ -16,8 +16,7 @@ const ArticleFootnotes = ({
|
|||
component="a"
|
||||
variant="body3"
|
||||
href={`#${footnote.refId}`}
|
||||
target="_blank"
|
||||
id={footnote.id.replace('#', '')}
|
||||
id={'fnt-' + footnote.id}
|
||||
>
|
||||
{footnote.refValue}
|
||||
</Typography>
|
||||
|
|
|
@ -24,11 +24,15 @@ const ImageBlock = (props: Props) => {
|
|||
type={BlockType.IMAGE}
|
||||
date={document?.modifiedAt ? new Date(document?.modifiedAt) : null}
|
||||
/>
|
||||
{data.alt.length > 0 && (
|
||||
{(data.caption || '').length > 0 && (
|
||||
<Caption>
|
||||
<Typography variant={'body2'} component={'p'}>
|
||||
{data.alt}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant={'body2'}
|
||||
component={'p'}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: data.captionHTML || '',
|
||||
}}
|
||||
/>
|
||||
</Caption>
|
||||
)}
|
||||
<ContentBlockFooter type="image" data={document} order={order} />
|
||||
|
|
|
@ -240,9 +240,8 @@ export const LightBox = ({ children, caption }: LightBoxProps) => {
|
|||
}
|
||||
isActive={isActive}
|
||||
ref={captionRef}
|
||||
>
|
||||
{caption}
|
||||
</LightBoxCaption>
|
||||
dangerouslySetInnerHTML={{ __html: caption }}
|
||||
></LightBoxCaption>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -85,6 +85,16 @@ export default function App({ Component, pageProps }: AppLayoutProps) {
|
|||
z-index: -1;
|
||||
}
|
||||
|
||||
.footnote {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
.anchor {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme='light'] {
|
||||
.light-mode-hidden {
|
||||
display: none !important;
|
||||
|
|
|
@ -104,7 +104,7 @@ export const getStaticProps = async ({ params }: GetStaticPropsContext) => {
|
|||
})
|
||||
.then((data) => ({
|
||||
...data,
|
||||
data: data.data.map((post) => ({
|
||||
data: (data.data || []).map((post) => ({
|
||||
...post,
|
||||
show: shows.find(
|
||||
(show) => show.id === (post as LPE.Podcast.Document).showId,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { CustomNextPage, GetServerSideProps } from 'next'
|
||||
import SEO from '../components/SEO/SEO'
|
||||
import { strapiApi } from '../services/strapi'
|
||||
import { LPE } from '../types/lpe.types'
|
||||
import { getPostLink } from '../utils/route.utils'
|
||||
|
||||
type PageProps = {}
|
||||
|
@ -13,37 +15,80 @@ const Page: CustomNextPage<PageProps> = (props) => {
|
|||
}
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async (ctx) => {
|
||||
const type = Array.isArray(ctx.query.type)
|
||||
? ctx.query.type[0]
|
||||
: ctx.query.type
|
||||
|
||||
if (!type || !['page', 'post'].includes(type))
|
||||
return {
|
||||
notFound: true,
|
||||
}
|
||||
|
||||
const id = Array.isArray(ctx.query.id) ? ctx.query.id[0] : ctx.query.id
|
||||
if (!id)
|
||||
return {
|
||||
notFound: true,
|
||||
}
|
||||
|
||||
// const { data, errors } = await unbodyApi.getDocById({
|
||||
// id,
|
||||
// includeDrafts: true,
|
||||
// })
|
||||
if (type === 'post') {
|
||||
const { data: shows } = await strapiApi.getPodcastShows({
|
||||
populateEpisodes: false,
|
||||
})
|
||||
|
||||
const data = undefined as any
|
||||
const errors = '' as string
|
||||
const {
|
||||
data: { data = [] },
|
||||
} = await strapiApi.getPosts({
|
||||
id: id,
|
||||
published: false,
|
||||
parseContent: false,
|
||||
})
|
||||
|
||||
if (!data || errors) {
|
||||
return {
|
||||
notFound: typeof errors === 'string' && errors.includes('Not found'),
|
||||
props: {},
|
||||
const post = data?.[0]
|
||||
if (post) {
|
||||
return {
|
||||
props: {},
|
||||
redirect: {
|
||||
destination: getPostLink(post.type, {
|
||||
id,
|
||||
postSlug: post.slug,
|
||||
showSlug:
|
||||
(post.type === 'podcast' &&
|
||||
shows.find(
|
||||
(show) => show.id === (post as LPE.Podcast.Document).showId,
|
||||
)?.slug) ||
|
||||
'',
|
||||
}),
|
||||
permanent: false,
|
||||
},
|
||||
notFound: false,
|
||||
}
|
||||
}
|
||||
} else if (type === 'page') {
|
||||
const { data: pages } = await strapiApi.getStaticPages({
|
||||
id: id,
|
||||
published: false,
|
||||
parseContent: false,
|
||||
})
|
||||
|
||||
const page = pages?.[0]
|
||||
|
||||
if (page) {
|
||||
return {
|
||||
props: {},
|
||||
redirect: {
|
||||
destination: getPostLink(page.type, {
|
||||
id,
|
||||
postSlug: page.slug,
|
||||
}),
|
||||
permanent: false,
|
||||
},
|
||||
notFound: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
props: {},
|
||||
redirect: {
|
||||
destination: getPostLink(data.type, {
|
||||
id,
|
||||
postSlug: data.slug,
|
||||
showSlug: (data.type === 'podcast' && data.show?.slug) || null,
|
||||
}),
|
||||
permanent: false,
|
||||
},
|
||||
notFound: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -75,6 +75,11 @@ export const transformStrapiHtmlContent = async ({
|
|||
|
||||
let root = htmlParser.parse(html, { parseNoneClosedTags: true })
|
||||
|
||||
// remove footnotes container as the content is already stored in sup tags
|
||||
root.querySelectorAll('section.footnotes-container').forEach((node) => {
|
||||
node.remove()
|
||||
})
|
||||
|
||||
let blockIndex = -1
|
||||
|
||||
for (const child of root.childNodes) {
|
||||
|
@ -82,24 +87,34 @@ export const transformStrapiHtmlContent = async ({
|
|||
continue
|
||||
}
|
||||
|
||||
const tagName = child.tagName.toLowerCase()
|
||||
const { node, footnotes } = parseFootnotes(child)
|
||||
|
||||
// remove footnotes before parsing the text content
|
||||
const clone = node.clone() as htmlParser.HTMLElement
|
||||
clone.querySelectorAll('a.footnote').forEach((a) => {
|
||||
a.remove()
|
||||
})
|
||||
|
||||
const text = clone.textContent || ''
|
||||
|
||||
const tagName = node.tagName.toLowerCase()
|
||||
const isFigure = tagName === 'figure'
|
||||
const isMedia = isFigure && !!child.querySelector('oembed')
|
||||
const isImage = isFigure && !isMedia && !!child.querySelector('img')
|
||||
const empty = child.text.length === 0
|
||||
const isMedia = isFigure && !!node.querySelector('oembed')
|
||||
const isImage = isFigure && !isMedia && !!node.querySelector('img')
|
||||
const empty = node.text.length === 0
|
||||
|
||||
if (!isFigure && empty) continue
|
||||
|
||||
blockIndex++
|
||||
|
||||
if (isImage) {
|
||||
const image = child.querySelector('img')
|
||||
const image = node.querySelector('img')
|
||||
if (!image) {
|
||||
blockIndex--
|
||||
continue
|
||||
}
|
||||
|
||||
const caption = child.textContent || ''
|
||||
const caption = text
|
||||
const alt = image.getAttribute('alt') || ''
|
||||
const url = image.getAttribute('src') || ''
|
||||
const width = parseInt(image.getAttribute('width') || '0', 10)
|
||||
|
@ -108,6 +123,7 @@ export const transformStrapiHtmlContent = async ({
|
|||
blocks.push({
|
||||
id: '',
|
||||
caption,
|
||||
captionHTML: node.querySelector('figcaption')?.innerHTML || '',
|
||||
type: 'image',
|
||||
width,
|
||||
height,
|
||||
|
@ -115,6 +131,7 @@ export const transformStrapiHtmlContent = async ({
|
|||
labels: [],
|
||||
order: blockIndex,
|
||||
url: url.startsWith('/') ? transformStrapiImageUrl(url) : url,
|
||||
footnotes,
|
||||
})
|
||||
|
||||
continue
|
||||
|
@ -123,7 +140,7 @@ export const transformStrapiHtmlContent = async ({
|
|||
if (isMedia) {
|
||||
const labels: LPE.Post.ContentBlockLabel[] = ['embed']
|
||||
|
||||
const oembed = child.querySelector('oembed')
|
||||
const oembed = node.querySelector('oembed')
|
||||
const url = oembed?.getAttribute('url') || ''
|
||||
if (!url) {
|
||||
blockIndex--
|
||||
|
@ -155,7 +172,7 @@ export const transformStrapiHtmlContent = async ({
|
|||
type: 'text',
|
||||
classNames: [],
|
||||
footnotes: [],
|
||||
html: child.outerHTML,
|
||||
html: node.outerHTML,
|
||||
labels,
|
||||
tagName: 'p',
|
||||
text: url,
|
||||
|
@ -166,13 +183,12 @@ export const transformStrapiHtmlContent = async ({
|
|||
})
|
||||
}
|
||||
|
||||
const text = child.text || ''
|
||||
const isHeading = tagName.startsWith('h')
|
||||
const id =
|
||||
child.id ||
|
||||
node.id ||
|
||||
(isHeading && slugify(text, { lower: true, trim: true })) ||
|
||||
`p-${blockIndex}`
|
||||
child.setAttribute('id', id)
|
||||
node.setAttribute('id', id)
|
||||
|
||||
if (isHeading) {
|
||||
toc.push({
|
||||
|
@ -186,13 +202,13 @@ export const transformStrapiHtmlContent = async ({
|
|||
|
||||
blocks.push({
|
||||
id: '',
|
||||
footnotes: [],
|
||||
html: child.outerHTML,
|
||||
text,
|
||||
footnotes,
|
||||
html: node.outerHTML,
|
||||
labels: [],
|
||||
tagName,
|
||||
text,
|
||||
order: blockIndex,
|
||||
classNames: Array.from(child.classList.values()),
|
||||
classNames: Array.from(node.classList.values()),
|
||||
type: 'text',
|
||||
} as LPE.Post.TextBlock)
|
||||
}
|
||||
|
@ -204,3 +220,47 @@ export const transformStrapiHtmlContent = async ({
|
|||
html: root.innerHTML,
|
||||
}
|
||||
}
|
||||
|
||||
const parseFootnotes = (
|
||||
node: htmlParser.HTMLElement,
|
||||
): {
|
||||
node: htmlParser.HTMLElement
|
||||
footnotes: LPE.Post.Footnotes
|
||||
} => {
|
||||
const footnotes = [] as LPE.Post.Footnotes
|
||||
|
||||
const clone = node.clone() as htmlParser.HTMLElement
|
||||
|
||||
clone.querySelectorAll('sup.footnote').forEach((sup, idx) => {
|
||||
const id = sup.getAttribute('data-id') || ''
|
||||
const index = parseInt(sup.getAttribute('data-index') || '', 10)
|
||||
const footnote = htmlParser.parse(sup.getAttribute('data-content') || '')
|
||||
|
||||
const refId = `fntref-${id}`
|
||||
const footnoteId = `fnt-${id}`
|
||||
|
||||
const anchor = htmlParser.parse(
|
||||
`<a class="footnote" href="#${footnoteId}"><sup><span class="anchor" id="${refId}"></span><span>[${index}]</span></sup></a>`,
|
||||
)
|
||||
|
||||
sup.replaceWith(anchor)
|
||||
|
||||
footnote.querySelectorAll('a').forEach((a) => {
|
||||
a.setAttribute('target', '_blank')
|
||||
})
|
||||
|
||||
footnotes.push({
|
||||
id,
|
||||
index,
|
||||
refId,
|
||||
refValue: anchor.textContent,
|
||||
valueHTML: footnote.outerHTML,
|
||||
valueText: footnote.textContent,
|
||||
})
|
||||
})
|
||||
|
||||
return {
|
||||
footnotes,
|
||||
node: clone,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ export namespace LPE {
|
|||
width: number
|
||||
height: number
|
||||
caption?: string
|
||||
captionHTML?: string
|
||||
placeholder?: string
|
||||
}
|
||||
}
|
||||
|
@ -35,13 +36,6 @@ export namespace LPE {
|
|||
}
|
||||
}
|
||||
|
||||
export namespace Tag {
|
||||
export type Document = {
|
||||
value: string
|
||||
count: number
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Post {
|
||||
export type Footnote = {
|
||||
index: number
|
||||
|
@ -92,6 +86,7 @@ export namespace LPE {
|
|||
order: number
|
||||
labels: ContentBlockLabel[]
|
||||
document?: D
|
||||
footnotes?: Post.Footnotes
|
||||
}
|
||||
|
||||
export type TextBlockEmbed = {
|
||||
|
@ -105,7 +100,6 @@ export namespace LPE {
|
|||
tagName: string
|
||||
classNames: string[]
|
||||
type: Extract<ContentBlockType, 'text'>
|
||||
footnotes: Post.Footnotes
|
||||
embed?: TextBlockEmbed
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue