Styling for Quote and Lead Content Blocks
This commit is contained in:
@@ -1,15 +1,60 @@
|
||||
import { fields } from '@keystatic/core'
|
||||
|
||||
import Markdoc, { type Node, type Schema } from '@markdoc/markdoc'
|
||||
import Markdoc, { type Node, type RenderableTreeNode, type Schema } from '@markdoc/markdoc'
|
||||
|
||||
import { generalBlocks } from '@/keystatic/blocks/general'
|
||||
|
||||
import { ARTICLES } from '../constants/collections'
|
||||
import { inlineOf } from './notes'
|
||||
import { eachTag, firstTag, isTag } from './tree'
|
||||
import type { NodeState, ResolveLink } from './types'
|
||||
|
||||
const { Tag } = Markdoc
|
||||
|
||||
function capitalise(children: RenderableTreeNode[]): void {
|
||||
const paragraph = firstTag(children, 'p')
|
||||
if (!paragraph) return
|
||||
|
||||
const [first, ...rest] = paragraph.children
|
||||
if (typeof first !== 'string' || !first) return
|
||||
|
||||
paragraph.children = [
|
||||
new Tag('span', { class: 'lead__cap' }, [first.slice(0, 1)]),
|
||||
first.slice(1),
|
||||
...rest,
|
||||
]
|
||||
}
|
||||
|
||||
function applyColumns(
|
||||
children: RenderableTreeNode[],
|
||||
columns: string[],
|
||||
state: NodeState,
|
||||
): void {
|
||||
let widest = 0
|
||||
eachTag(children, 'tr', (row) => {
|
||||
widest = Math.max(widest, row.children.length)
|
||||
|
||||
row.children.forEach((cell, index) => {
|
||||
const kind = columns[index]
|
||||
if (!isTag(cell) || !kind || kind === 'default') return
|
||||
if (kind === 'rowheader') {
|
||||
if (cell.name !== 'td') return
|
||||
cell.name = 'th'
|
||||
cell.attributes.scope = 'row'
|
||||
return
|
||||
}
|
||||
|
||||
cell.attributes.class = [cell.attributes.class, kind].filter(Boolean).join(' ')
|
||||
})
|
||||
})
|
||||
|
||||
if (widest && widest !== columns.length)
|
||||
state.problems.push({
|
||||
level: 'warning',
|
||||
message: `A table wrapper lists ${columns.length} column types for a table ${widest} columns wide.`,
|
||||
})
|
||||
}
|
||||
|
||||
const generated =
|
||||
fields.markdoc.createMarkdocConfig({
|
||||
components: generalBlocks(ARTICLES),
|
||||
@@ -103,5 +148,13 @@ export function createTags(state: NodeState, resolveLink: ResolveLink): Record<s
|
||||
]
|
||||
},
|
||||
},
|
||||
lead: {
|
||||
...generated.lead,
|
||||
transform(node, config) {
|
||||
const children = node.transformChildren(config)
|
||||
capitalise(children)
|
||||
return new Tag('Lead', node.transformAttributes(config), children)
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
25
src/lib/markdoc/tree.ts
Normal file
25
src/lib/markdoc/tree.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import Markdoc, { type RenderableTreeNode, type Tag } from '@markdoc/markdoc'
|
||||
|
||||
export const isTag = (node: RenderableTreeNode): node is Tag => Markdoc.Tag.isTag(node)
|
||||
|
||||
export function firstTag(nodes: RenderableTreeNode[], name: string): Tag | null {
|
||||
for (const node of nodes) {
|
||||
if (!isTag(node)) continue
|
||||
if (node.name === name) return node
|
||||
const found = firstTag(node.children, name)
|
||||
if (found) return found
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export function eachTag(
|
||||
nodes: RenderableTreeNode[],
|
||||
name: string,
|
||||
visit: (tag: Tag) => void,
|
||||
): void {
|
||||
for (const node of nodes) {
|
||||
if (!isTag(node)) continue
|
||||
if (node.name === name) visit(node)
|
||||
else eachTag(node.children, name, visit)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user