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 },
+ },
+ })
+ })
+ }
+}