From 692b33f9fcba1551a2b2f31ea083b18faa22f241 Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Fri, 2 Jun 2023 10:56:12 -0600 Subject: [PATCH] feat(vecs): transform mkdocs admonition to supabase admonition --- apps/docs/components/Admonition.tsx | 9 +- apps/docs/lib/mdx/plugins/remarkAdmonition.ts | 105 ++++++++++++++++++ apps/docs/pages/guides/ai/python/[slug].tsx | 3 +- 3 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 apps/docs/lib/mdx/plugins/remarkAdmonition.ts diff --git a/apps/docs/components/Admonition.tsx b/apps/docs/components/Admonition.tsx index 42f7049f864..8a85475d929 100644 --- a/apps/docs/components/Admonition.tsx +++ b/apps/docs/components/Admonition.tsx @@ -1,13 +1,12 @@ -import { FC } from 'react' -import { IconInfo, IconHelpCircle, IconAlertTriangle } from 'ui' +import { PropsWithChildren } from 'react' +import { IconAlertTriangle, IconHelpCircle, IconInfo } from 'ui' -interface Props { +export interface AdmonitionProps { type: 'note' | 'tip' | 'info' | 'caution' | 'danger' label?: string - children: any } -const Admonition: FC = ({ type = 'note', label, children }) => { +const Admonition = ({ type = 'note', label, children }: PropsWithChildren) => { return (
{ + const [firstChild] = paragraph.children + + if (firstChild?.type === 'text') { + const match = firstChild.value.match(/^!!! ?(.*?)\n(.*)/s) + + if (!match) { + return + } + + // Extract the admonition type along with the remaining text + const [, type, value] = match + + // Rewrite the node's value to remove the admonition syntax + firstChild.value = value + + // Extract sibling nodes that should be linked to this admonition + const siblingsToNest = extractLinkedSiblings(parent, paragraph, index) + + const children: any[] = [...paragraph.children, ...siblingsToNest] + + // Generate a Supabase Admonition JSX element + const admonitionElement: MdxJsxFlowElement = { + type: 'mdxJsxFlowElement', + name: 'Admonition', + attributes: [ + { + type: 'mdxJsxAttribute', + name: 'type', + value: mapAdmonitionType(type), + }, + ], + children, + } + + // Overwrite original node with new element + parent.children.splice(index, 1, admonitionElement) + } + }) + } +} + +/** + * Identifies sibling nodes that should be linked to this admonition + * based on their indent level (ie. 4 spaces). + * + * Iterates through proceeding siblings until one is found that is + * not indented relative to the original node. + * + * Splices the discovered siblings out of the original parent and returns them. + */ +function extractLinkedSiblings(parent: Parent, node: Node, index: number, indentAmount = 4) { + const { column } = node.position.start + + let nextSibling: Content + let i = index + + do { + nextSibling = parent.children[++i] + } while (nextSibling?.position && nextSibling.position.start.column === column + indentAmount) + + return parent.children.splice(index + 1, i - index - 1) +} + +/** + * Maps `mkdocs-material` Admonition types to Supabase Admonition types. + * + * https://squidfunk.github.io/mkdocs-material/reference/admonitions/#supported-types + */ +function mapAdmonitionType(type: string): AdmonitionProps['type'] { + switch (type) { + case 'quote': + case 'example': + case 'note': + return 'note' + case 'tip': + return 'tip' + case 'warning': + return 'caution' + case 'failure': + case 'bug': + case 'danger': + return 'danger' + case 'abstract': + case 'question': + case 'info': + default: + return 'info' + } +} + +export default remarkMkDocsAdmonition diff --git a/apps/docs/pages/guides/ai/python/[slug].tsx b/apps/docs/pages/guides/ai/python/[slug].tsx index c4299969164..1010c296e5c 100644 --- a/apps/docs/pages/guides/ai/python/[slug].tsx +++ b/apps/docs/pages/guides/ai/python/[slug].tsx @@ -7,6 +7,7 @@ import remarkGfm from 'remark-gfm' import components from '~/components' import Layout from '~/layouts/DefaultGuideLayout' import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform' +import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition' import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle' // We fetch these docs at build time from an external repo @@ -117,7 +118,7 @@ export const getStaticProps: GetStaticProps = async ({ pa const mdxSource = await serialize(source, { mdxOptions: { - remarkPlugins: [remarkGfm, [removeTitle, meta.title]], + remarkPlugins: [remarkGfm, remarkMkDocsAdmonition, [removeTitle, meta.title]], rehypePlugins: [[linkTransform, urlTransform], rehypeSlug], }, })