diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c9408234..74e0ddb5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5785,7 +5785,7 @@ packages: dependencies: lilconfig: 2.1.0 postcss: 8.4.31 - yaml: 2.3.3 + yaml: 2.3.4 /postcss-nested@6.0.1(postcss@8.4.31): resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} @@ -6179,7 +6179,7 @@ packages: estree-util-value-to-estree: 3.0.1 toml: 3.0.0 unified: 11.0.4 - yaml: 2.3.3 + yaml: 2.3.4 dev: false /remark-mdx@3.0.0: @@ -7335,8 +7335,8 @@ packages: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} dev: true - /yaml@2.3.3: - resolution: {integrity: sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==} + /yaml@2.3.4: + resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} engines: {node: '>= 14'} /yargs-parser@18.1.3: diff --git a/site/pages/blog/gm.mdx b/site/pages/blog/gm.mdx new file mode 100644 index 00000000..061ff612 --- /dev/null +++ b/site/pages/blog/gm.mdx @@ -0,0 +1,13 @@ +--- +layout: blog +authors: + - "[jxom](https://twitter.com/_jxom)" + - "[awkweb](https://twitter.com/awkweb)" +date: November 25, 2023 +--- + +# gm + +::authors + +we're so back. \ No newline at end of file diff --git a/src/app/components/Authors.css.ts b/src/app/components/Authors.css.ts new file mode 100644 index 00000000..1159769e --- /dev/null +++ b/src/app/components/Authors.css.ts @@ -0,0 +1,32 @@ +import { style } from '@vanilla-extract/css' +import { fontSizeVars, primitiveColorVars } from '../styles/vars.css.js' + +export const root = style({ + color: primitiveColorVars.text3, + fontSize: fontSizeVars[14], +}) + +export const authors = style( + { + color: primitiveColorVars.text, + }, + 'authors', +) + +export const link = style( + { + textDecoration: 'underline', + textUnderlineOffset: '2px', + ':hover': { + color: primitiveColorVars.text2, + }, + }, + 'link', +) + +export const separator = style( + { + color: primitiveColorVars.text3, + }, + 'separator', +) diff --git a/src/app/components/Authors.tsx b/src/app/components/Authors.tsx new file mode 100644 index 00000000..8dfa3bcd --- /dev/null +++ b/src/app/components/Authors.tsx @@ -0,0 +1,47 @@ +import * as styles from './Authors.css.js' + +export type AuthorsProps = { + authors?: string | string[] + date?: string +} + +export function Authors({ authors: authors_, date }: AuthorsProps) { + const authors = (() => { + if (!authors_) return undefined + if (Array.isArray(authors_)) return authors_ + return authors_.split(',').map((author) => author.trim()) + })() + return ( +
+ {date} + {authors && date ? ' by ' : 'By '} + + {authors?.map((author, index) => { + const { text, url } = parseAuthor(author) + return ( + <> + {url ? ( + + {text} + + ) : ( + text + )} + {index < authors.length - 2 && , } + {index < authors.length - 1 && & } + + ) + })} + +
+ ) +} + +function parseAuthor(author: string) { + const match = author.match(/\[(.+)\]\((.+)\)/) + if (!match) return { text: author, url: undefined } + return { + text: match[1], + url: match[2], + } +} diff --git a/src/app/components/mdx/Div.tsx b/src/app/components/mdx/Div.tsx index 03c894c0..6cfec6b0 100644 --- a/src/app/components/mdx/Div.tsx +++ b/src/app/components/mdx/Div.tsx @@ -1,6 +1,7 @@ import { clsx } from 'clsx' import { type DetailedHTMLProps, type HTMLAttributes } from 'react' +import { Authors } from '../Authors.js' import { AutolinkIcon } from './AutolinkIcon.js' import { CodeBlock } from './CodeBlock.js' import { CodeGroup } from './CodeGroup.js' @@ -13,6 +14,13 @@ export function Div(props: DetailedHTMLProps, HTM const className = clsx(props.className, styles.root) if (props.className === 'code-group') return + if ('data-authors' in props) + return ( + + ) if ('data-autolink-icon' in props) return if ('data-rehype-pretty-code-title' in props) diff --git a/src/app/layouts/DocsLayout.tsx b/src/app/layouts/DocsLayout.tsx index 179451a3..70c7c75e 100644 --- a/src/app/layouts/DocsLayout.tsx +++ b/src/app/layouts/DocsLayout.tsx @@ -24,11 +24,17 @@ export function DocsLayout({ const { frontmatter } = usePageData() const showOutline = (() => { - if (frontmatter && 'outline' in frontmatter) return frontmatter.outline + if (frontmatter) { + if ('outline' in frontmatter) return frontmatter.outline + if (frontmatter.layout === 'blog') return false + } return true })() const showSidebar = (() => { - if (frontmatter && 'sidebar' in frontmatter) return frontmatter.sidebar + if (frontmatter) { + if ('sidebar' in frontmatter) return frontmatter.sidebar + if (frontmatter.layout === 'blog') return false + } return Boolean(sidebar) })() diff --git a/src/app/types.ts b/src/app/types.ts index 11f23f0b..dada2c2a 100644 --- a/src/app/types.ts +++ b/src/app/types.ts @@ -3,7 +3,10 @@ import * as React from 'react' export type Frontmatter = { [key: string]: unknown + author?: string + date?: string description?: string + layout?: 'blog' outline?: boolean sidebar?: boolean title?: string diff --git a/src/vite/plugins/mdx.ts b/src/vite/plugins/mdx.ts index 93ec72b2..834f3831 100644 --- a/src/vite/plugins/mdx.ts +++ b/src/vite/plugins/mdx.ts @@ -1,20 +1,21 @@ import mdxPlugin from '@mdx-js/rollup' -import remarkDirective from 'remark-directive' -import remarkFrontmatter from 'remark-frontmatter' -import remarkGfm from 'remark-gfm' -import remarkMdxFrontmatter from 'remark-mdx-frontmatter' -import { type PluginOption } from 'vite' import { h } from 'hastscript' import rehypeAutolinkHeadings from 'rehype-autolink-headings' import rehypePrettyCode from 'rehype-pretty-code' import rehypeSlug from 'rehype-slug' +import remarkDirective from 'remark-directive' +import remarkFrontmatter from 'remark-frontmatter' +import remarkGfm from 'remark-gfm' +import remarkMdxFrontmatter from 'remark-mdx-frontmatter' import { createDiffProcessor, createFocusProcessor, createHighlightProcessor, getHighlighter, } from 'shiki-processor' +import { type PluginOption } from 'vite' +import { remarkAuthors } from './remark/authors.js' import { remarkCallout } from './remark/callout.js' import { remarkCodeGroup } from './remark/code-group.js' import { remarkCode } from './remark/code.js' @@ -39,6 +40,7 @@ export function mdx(): PluginOption { remarkSteps, remarkStrongBlock, remarkSubheading, + remarkAuthors, ], rehypePlugins: [ [ diff --git a/src/vite/plugins/remark/authors.ts b/src/vite/plugins/remark/authors.ts new file mode 100644 index 00000000..ef4465a2 --- /dev/null +++ b/src/vite/plugins/remark/authors.ts @@ -0,0 +1,28 @@ +/// +/// + +import type { Root } from 'mdast' +import { visit } from 'unist-util-visit' +import { parse } from 'yaml' + +export function remarkAuthors() { + return (tree: Root) => { + visit(tree, (node, index, parent) => { + if (node.type !== 'leafDirective') return + if (node.name !== 'authors') return + if (!index) return + + const frontMatterNode = parent?.children.find((child) => child.type === 'yaml') as any + if (!frontMatterNode) return + + const data = parse(frontMatterNode.value) + ;(parent?.children[index - 1] as any).children.push({ + type: 'paragraph', + data: { + hName: 'div', + hProperties: { 'data-authors': data.authors.join(','), 'data-date': data.date }, + }, + }) + }) + } +}