1
1
mirror of https://github.com/mdx-js/mdx.git synced 2024-09-11 15:05:32 +03:00

Add a nice blog page (#1719)

Reviewed-by: Christian Murphy <christian.murphy.42@gmail.com>
This commit is contained in:
Titus 2021-10-06 20:00:21 +02:00 committed by GitHub
parent 4a3261be56
commit 7b72f6ff33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 161 additions and 40 deletions

View File

@ -554,6 +554,23 @@ button:focus {
border-radius: 3px;
}
.card {
display: block;
padding: calc(1 * (1em + 1ex));
margin: calc(2 * (1em + 1ex)) 0;
background-color: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 0 0 0.2em rgba(3, 102, 214, 0),
0 13px 27px -5px rgba(50, 50, 93, 0.25), 0 8px 16px -8px rgba(0, 0, 0, 0.3),
0 -6px 16px -6px rgba(0, 0, 0, 0.025);
background-image: radial-gradient(
ellipse at 100% 100%,
rgb(252 180 45 / 10%) 20%,
transparent 80%
);
}
#markdown-for-thecomponent-era {
font-weight: 600;
}
@ -573,11 +590,11 @@ button:focus {
padding: calc(1em + 1ex);
}
.home-preview > :is(h1, h2, h3, h4):first-child {
:is(.home-preview, .card) > :is(h1, h2, h3, h4, p, .block):first-child {
margin-top: 0;
}
.home-preview > :is(h1, h2, h3, h4):last-child {
:is(.home-preview, .card) > :is(h1, h2, h3, h4, p, .block):last-child {
margin-bottom: 0;
}
@ -841,6 +858,15 @@ button:focus {
background-color: var(--hl);
color: var(--gray-0);
}
.card {
background-color: var(--gray-9);
background-image: radial-gradient(
ellipse at 100% 100%,
rgb(252 180 45 / 10%) 20%,
transparent 80%
);
}
}
@media (min-width: 22em) {

View File

@ -0,0 +1,75 @@
import React, {createElement} from 'react'
import apStyleTitleCase from 'ap-style-title-case'
import {toH} from 'hast-to-hyperscript'
import {sortItems} from './sort.js'
const dateTimeFormat = new Intl.DateTimeFormat('en')
export const BlogEntry = (props) => {
const {item} = props
const {name, data = {}} = item
const {matter = {}, meta = {}} = data
const title = matter.title || meta.title
const defaultTitle = apStyleTitleCase(
name.replace(/\/$/, '').split('/').pop()
)
const description = matter.description || meta.description
const time = (
meta.readingTime
? Array.isArray(meta.readingTime)
? meta.readingTime
: [meta.readingTime, meta.readingTime]
: []
).map((d) => Math.ceil(d))
let timeLabel
if (time.length > 1 && time[0] !== time[1]) {
timeLabel = time[0] + '-' + time[1] + ' minutes'
} else if (time[0]) {
timeLabel = time[0] + ' minute' + (time[0] > 1 ? 's' : '')
}
return (
<div className="card">
<h3>
<a href={name}>{title || defaultTitle}</a>
</h3>
<div>
{meta.descriptionHast ? (
toH(createElement, meta.descriptionHast)
) : description ? (
<p>{description}</p>
) : null}
<span>
<a href={name}>Read more »</a>
</span>
</div>
<div
style={{display: 'flex', justifyContent: 'space-between'}}
className="block"
>
<div>
<small>By {meta.author}</small>
<br />
<small>Reading time: {timeLabel}</small>
</div>
<div style={{marginLeft: 'auto', textAlign: 'right'}}>
<small>Published on {dateTimeFormat.format(meta.published)}</small>
</div>
</div>
</div>
)
}
export const BlogGroup = (props) => {
const {items, className, sort = 'navSortSelf,meta.title', ...rest} = props
const sorted = sortItems(items, sort)
return (
<>
{sorted.map((d) => (
<BlogEntry key={d.name} {...rest} item={d} />
))}
</>
)
}

View File

@ -19,13 +19,21 @@ export const NavGroup = (props) => {
export const NavItem = (props) => {
const {item, name: activeName, includeDescription, includePublished} = props
const {name, children, data = {}} = item
const {matter = {}, meta = {}, navLabel, navExcludeGroup, navSortItems} = data
const {matter = {}, meta = {}, navExcludeGroup, navSortItems} = data
const title = matter.title || meta.title
const description = matter.description || meta.description
const published = matter.published || meta.published
const defaultTitle = apStyleTitleCase(
name.replace(/\/$/, '').split('/').pop()
)
let description
let published
if (includeDescription) {
description = matter.description || meta.description
}
if (includePublished && (matter.published || meta.published)) {
published = dateTimeFormat.format(matter.published || meta.published)
}
return (
<li>
@ -36,11 +44,8 @@ export const NavItem = (props) => {
) : (
defaultTitle
)}
{navLabel ? <sup>[{navLabel}]</sup> : null}
{includeDescription && description ? ' — ' + description : null}
{includePublished && published
? ' — ' + dateTimeFormat.format(published)
: null}
{description ? ' — ' + description : null}
{published ? ' — ' + published : null}
{!navExcludeGroup && children.length > 0 ? (
<NavGroup items={children} sort={navSortItems} name={activeName} />
) : null}

View File

@ -1,4 +1,4 @@
import {NavGroup} from '../_component/nav.server.js'
import {BlogGroup} from '../_component/blog.server.js'
export const navExcludeGroup = true
export const navSortItems = 'navSortSelf,meta.published:desc'
@ -12,7 +12,7 @@ export const navSortItems = 'navSortSelf,meta.published:desc'
return (
<nav>
<NavGroup items={category.children} sort={navSortItems} includePublished />
<BlogGroup items={category.children} sort={navSortItems} />
</nav>
)
})()

View File

@ -1,4 +1,4 @@
[MDX Blog](/blog)
{/* To do: make the below a callout */}
> [ZEIT is now Vercel](https://rauchg.com/2020/vercel).
> The below is kept as is for historical purposes.

View File

@ -1,3 +1,5 @@
export const navExclude = true
# Migrating from v0 to v1
Unfortunately, weve had to introduce a few breaking changes, so weve written a

View File

@ -8,9 +8,12 @@ import {pipeToNodeWritable} from 'react-server-dom-webpack/writer'
import pAll from 'p-all'
import {globby} from 'globby'
import {sitemap} from 'xast-util-sitemap'
import {unified} from 'unified'
import rehypeSanitize from 'rehype-sanitize'
import {toXml} from 'xast-util-to-xml'
import {Layout} from '../docs/_component/layout.server.js'
import {config} from '../docs/_config.js'
import {schema} from './schema-description.js'
main().catch((error) => {
throw error
@ -42,6 +45,13 @@ async function main() {
const {default: Content, ...data} = await import(url.href)
// Sanitize the HAST description:
if (data.meta.descriptionHast) {
data.meta.descriptionHast = unified()
.use(rehypeSanitize, schema)
.runSync(data.meta.descriptionHast)
}
return {name, url, ghUrl, nljsonUrl, jsonUrl, data, Content}
}),
{concurrency: 6}

View File

@ -49,7 +49,10 @@ const options = {
rehypePlugins: [
unifiedInferRemoteMeta,
unifiedInferGitMeta,
[rehypeInferDescriptionMeta, {inferDescriptionHast: true}],
[
rehypeInferDescriptionMeta,
{inferDescriptionHast: true, truncateSize: 280}
],
rehypeInferReadingTimeMeta,
rehypeInferTitleMeta,
[rehypeShiftHeading, {shift: 1}],

View File

@ -15,35 +15,10 @@ import rehypeStringify from 'rehype-stringify'
import captureWebsite from 'capture-website'
import chromium from 'chrome-aws-lambda'
import {config} from '../docs/_config.js'
import {schema} from './schema-description.js'
const dateTimeFormat = new Intl.DateTimeFormat('en')
const schema = {
strip: ['script', 'style'],
ancestors: {},
protocols: {href: ['http', 'https']},
tagNames: [
'ul',
'ol',
'li',
'pre',
'code',
'strong',
'p',
'b',
'em',
'i',
'strike',
's',
'del',
'a'
],
attributes: {
a: ['href'],
'*': []
}
}
main().catch((error) => {
throw error
})

View File

@ -0,0 +1,25 @@
export const schema = {
strip: ['script', 'style'],
ancestors: {},
protocols: {href: ['http', 'https']},
tagNames: [
'ul',
'ol',
'li',
'pre',
'code',
'strong',
'p',
'b',
'em',
'i',
'strike',
's',
'del',
'a'
],
attributes: {
a: ['href'],
'*': []
}
}