diff --git a/apps/nextjs/next.config.mjs b/apps/nextjs/next.config.mjs
index 3b0aef7..c6c810b 100644
--- a/apps/nextjs/next.config.mjs
+++ b/apps/nextjs/next.config.mjs
@@ -7,7 +7,7 @@ const config = {
reactStrictMode: true,
/** Enables hot reloading for local packages without a build step */
- transpilePackages: [],
+ transpilePackages: ["@acme/markdoc-base", "@acme/ui"],
/** We already do linting and typechecking as separate tasks in CI */
eslint: { ignoreDuringBuilds: true },
typescript: { ignoreBuildErrors: true },
diff --git a/apps/nextjs/src/app/layout.tsx b/apps/nextjs/src/app/layout.tsx
index 15234c3..41c01bb 100644
--- a/apps/nextjs/src/app/layout.tsx
+++ b/apps/nextjs/src/app/layout.tsx
@@ -8,26 +8,9 @@ const fontSans = Inter({
variable: "--font-sans",
});
-/**
- * Since we're passing `headers()` to the `TRPCReactProvider` we need to
- * make the entire app dynamic. You can move the `TRPCReactProvider` further
- * down the tree (e.g. /dashboard and onwards) to make part of the app statically rendered.
- */
-
export const metadata: Metadata = {
title: "Create T3 Turbo",
description: "Simple monorepo with shared backend for web & mobile apps",
- openGraph: {
- title: "Create T3 Turbo",
- description: "Simple monorepo with shared backend for web & mobile apps",
- url: "https://create-t3-turbo.vercel.app",
- siteName: "Create T3 Turbo",
- },
- twitter: {
- card: "summary_large_image",
- site: "@jullerino",
- creator: "@jullerino",
- },
};
export default function Layout({ children }: { children: React.ReactNode }) {
diff --git a/apps/nextjs/src/app/page.tsx b/apps/nextjs/src/app/page.tsx
index da3abe2..5db98ff 100644
--- a/apps/nextjs/src/app/page.tsx
+++ b/apps/nextjs/src/app/page.tsx
@@ -1,7 +1,19 @@
-export default function HomePage() {
+import path from "path";
+import React from "react";
+import { notFound } from "next/navigation";
+
+import { components, Markdoc, parseContent } from "@acme/markdoc-base";
+
+export default async function HomePage() {
+ const filePath = path.join(path.resolve(), "./src/content/test.md");
+
+ const pageContent = await parseContent(filePath);
+
+ if (!pageContent) notFound();
+
return (
- Hello World
+ {Markdoc.renderers.react(pageContent.content, React, components)}
- )
+ );
}
diff --git a/apps/nextjs/src/content/test.md b/apps/nextjs/src/content/test.md
new file mode 100644
index 0000000..dc45e24
--- /dev/null
+++ b/apps/nextjs/src/content/test.md
@@ -0,0 +1,47 @@
+---
+title: Hello World
+description: A short summary about this awesome page
+---
+
+Corporis cognosces Peleus tibi
+
+## Spes terra illis cum silvas gaudere videtque
+
+Lorem markdownum tu peto? Fessa peteretur tyranni nota aquaticus iussere, io
+vivere, conditur meum ut lassaque. Adsiduo perveni Atrides postquam alte illa et
+spernenda, late ferarum, modo. Reticere munus sui vertit est nescius adhuc
+insuperabile nidos! Tumidam *hospes* ferrum a pulsat inferius: aut es marmoris!
+
+> Pectore ursaeque, fuit prolisque erit amnesque: nam datis viro caecaque
+> resupino notavi. Quoque dolentius multi, has quicquam magni, ruunt omnia
+> imagine? Delphice quae illo est cruor adhuc telisque et manu, amor,
+> *causamque* te vestes; rerum.
+
+## Carituraque debet penetrabile alta imagine
+
+Egerat solent, Iuppiter non rictus, Parnasosque illa; talia. Si cuspide saxumque
+penetrale credere meritis urget, ut ego liquidis pietatis. Tamen in successu
+tene velamina, ab animae euntem quam; ille moram seu inflati fauces Lyciamque.
+Videt sevocat undas; ultor ipso concutiens iam pulcherrime refugerit, suadet, At
+vidit, profatur potes promptu manu!
+
+Cadit **tangit quo** sine valuere nulla, Philemon quoque luctantiaque. [Ante
+exsecrantia](http://orant.com/sed.php) alis iam! Fluctusque utinam pennis deum
+pocula cum. Tetigit avis aequoreis posses alto Tyriis, voce reor habet solet
+postquam *adsuetaque* regnat medium locis.
+
+## Tanto ortas harenis collaque dant
+
+Mora dissimulat ac, visa vires sortes inferius **dei quod** frigus, lumina
+Samon, mortis. **Parte fluctus** tum, in invitam satis, *nominat retentis
+videre* finis tu et mendacia nomen. Huic illic abdita Terram.
+
+Est verso praedam repetitaque mons esse, mora petenti haec scopulus ille
+medioque, ne verumque, ales. Sideraque invidit. Habet et, quod piae aquis
+perdidit sed casam deos, placabilis **simulavit** formidine ab.
+
+Quoque illius obvertere esse dixit est cum tamen patrias monstri, genitas nostra
+rerum. Mihi movit Rhodopen dolores refers summo, commonuit vera clamat versa et
+uvis **monte summoque rarior**, Venus, Imbreus. Lacer tamen cupit, trans sacras
+territaque, custodemque saltem Procne punior. Sparsos debita spes arma asperitas
+turis ostendens dixerat!
diff --git a/packages/helpers/index.ts b/packages/helpers/index.ts
new file mode 100644
index 0000000..6a2d481
--- /dev/null
+++ b/packages/helpers/index.ts
@@ -0,0 +1 @@
+export { cn } from "./src/cn";
diff --git a/packages/helpers/package.json b/packages/helpers/package.json
new file mode 100644
index 0000000..29b9a9f
--- /dev/null
+++ b/packages/helpers/package.json
@@ -0,0 +1,40 @@
+{
+ "name": "@acme/helpers",
+ "private": true,
+ "version": "0.1.0",
+ "exports": {
+ ".": "./index.ts"
+ },
+ "typesVersions": {
+ "*": {
+ "*": [
+ "src/*"
+ ]
+ }
+ },
+ "license": "MIT",
+ "scripts": {
+ "clean": "rm -rf .turbo node_modules",
+ "lint": "eslint .",
+ "format": "prettier --check . --ignore-path ../../.gitignore",
+ "typecheck": "tsc --noEmit"
+ },
+ "dependencies": {
+ "clsx": "2.0.0",
+ "tailwindcss": "3.3.6",
+ "tailwind-merge": "2.1.0"
+ },
+ "devDependencies": {
+ "@acme/eslint-config": "workspace:0.2.0",
+ "@acme/prettier-config": "workspace:0.1.0",
+ "@acme/tsconfig": "workspace:0.1.0",
+ "eslint": "8.55.0",
+ "typescript": "5.3.3"
+ },
+ "eslintConfig": {
+ "extends": [
+ "@acme/eslint-config/base"
+ ]
+ },
+ "prettier": "@acme/prettier-config"
+}
diff --git a/packages/ui/src/lib/utils.ts b/packages/helpers/src/cn.ts
similarity index 100%
rename from packages/ui/src/lib/utils.ts
rename to packages/helpers/src/cn.ts
diff --git a/packages/helpers/tsconfig.json b/packages/helpers/tsconfig.json
new file mode 100644
index 0000000..7a26a27
--- /dev/null
+++ b/packages/helpers/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "@acme/tsconfig/base.json",
+ "compilerOptions": {
+ "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
+ },
+ "include": ["*.ts", "src"],
+ "exclude": ["node_modules"]
+}
diff --git a/packages/markdoc-base/index.ts b/packages/markdoc-base/index.ts
index 543c554..7226c60 100644
--- a/packages/markdoc-base/index.ts
+++ b/packages/markdoc-base/index.ts
@@ -2,6 +2,6 @@ import Markdoc from "@markdoc/markdoc";
import { components, config } from "./src";
-
-
export { Markdoc, config, components };
+
+export * from "./src/helpers";
diff --git a/packages/markdoc-base/package.json b/packages/markdoc-base/package.json
index e380d3e..966ac64 100644
--- a/packages/markdoc-base/package.json
+++ b/packages/markdoc-base/package.json
@@ -20,7 +20,12 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
- "@markdoc/markdoc": "0.4.0"
+ "@markdoc/markdoc": "0.4.0",
+ "zod": "3.22.4",
+ "zod-matter": "0.1.1",
+ "string-strip-html": "13.4.3",
+ "@acme/markdoc-heading": "workspace:0.1.0",
+ "@acme/helpers": "workspace:0.1.0"
},
"devDependencies": {
"@acme/eslint-config": "workspace:0.2.0",
diff --git a/packages/markdoc-base/src/frontmatter.ts b/packages/markdoc-base/src/frontmatter.ts
new file mode 100644
index 0000000..e4033af
--- /dev/null
+++ b/packages/markdoc-base/src/frontmatter.ts
@@ -0,0 +1,13 @@
+import { z } from "zod";
+import { parse as parseFrontmatter } from "zod-matter";
+
+export function getFrontmatter(fileContent: string) {
+ const frontmatterProps = z.object({
+ title: z.string(),
+ description: z.string().optional(),
+ });
+
+ const { data: frontmatter } = parseFrontmatter(fileContent, frontmatterProps);
+
+ return frontmatter;
+}
diff --git a/packages/markdoc-base/src/helpers.ts b/packages/markdoc-base/src/helpers.ts
new file mode 100644
index 0000000..8f66336
--- /dev/null
+++ b/packages/markdoc-base/src/helpers.ts
@@ -0,0 +1,92 @@
+import type { PathLike } from "node:fs";
+import fs from "node:fs/promises";
+import type { Node as MarkdocNode, Tag } from "@markdoc/markdoc";
+import Markdoc from "@markdoc/markdoc";
+import { stripHtml } from "string-strip-html";
+
+import { getFrontmatter } from "./frontmatter";
+import { config } from "./index";
+
+interface HeadingNode extends MarkdocNode {
+ type: "heading";
+ attributes: {
+ level: 1 | 2 | 3 | 4 | 5 | 6;
+ id: string;
+ [key: string]: unknown;
+ };
+}
+
+export interface TableOfContents {
+ id: string;
+ title: string;
+ level: number;
+ children?: TableOfContents[];
+}
+
+export async function getFileContent(filePath: PathLike | fs.FileHandle) {
+ try {
+ return await fs.readFile(filePath, { encoding: "utf-8" });
+ } catch (e) {
+ return null;
+ }
+}
+
+export async function parseContent(filePath: PathLike | fs.FileHandle) {
+ const fileContent = await getFileContent(filePath);
+
+ if (!fileContent) return;
+
+ const frontmatter = getFrontmatter(fileContent);
+
+ const ast = Markdoc.parse(fileContent);
+ const content = Markdoc.transform(ast, config);
+
+ // since RenderableTreeNode could be a string
+ // we use the `Tag` type for content
+ // otherwise we get some type issues and I have no idea
+ // how I could solve it
+ const headings = ((content as Tag).children as Tag[]).filter((ele) => {
+ return ele.name == "Heading";
+ });
+
+ return {
+ content,
+ ...frontmatter,
+ toc: generateTableOfContents(headings),
+ };
+}
+
+export function generateTableOfContents(headings: Tag[]) {
+ const sections: TableOfContents[] = [];
+
+ for (const heading of headings) {
+ const attributes = (heading as unknown as HeadingNode).attributes;
+
+ if (attributes.level == 2 || attributes.level == 3) {
+ const strippedTitle = stripHtml(Markdoc.renderers.html(heading)).result;
+
+ if (attributes.level == 3) {
+ if (!sections[sections.length - 1]) {
+ throw new Error(
+ `Cannot add "h3" to table of contents without a preceding "h2" - Heading Title: ${strippedTitle}`,
+ );
+ }
+
+ sections[sections.length - 1]?.children!.push({
+ id: attributes.id,
+ level: attributes.level,
+ title: strippedTitle,
+ });
+ } else {
+ sections.push({
+ id: attributes.id,
+ level: attributes.level,
+ title: strippedTitle,
+ children: [],
+ });
+ }
+ }
+ }
+
+ return sections;
+}
diff --git a/packages/markdoc-base/src/index.ts b/packages/markdoc-base/src/index.ts
index de828da..29531ba 100644
--- a/packages/markdoc-base/src/index.ts
+++ b/packages/markdoc-base/src/index.ts
@@ -1,152 +1,139 @@
import type { Config } from "@markdoc/markdoc";
+import { Heading, config as headingConfig } from "@acme/markdoc-heading";
+
const config: Config = {
- // nodes: {
- // paragraph: {
- // render: "Paragraph",
- // },
- // link: {
- // ...markdocNodes.link,
- // render: "CustomLink",
- // },
- // heading: {
- // render: "Heading",
- // attributes: {
- // id: { type: String },
- // level: { type: Number, required: true },
- // },
- // transform(node, config) {
- // const attributes = node.transformAttributes(config)
- // const children = node.transformChildren(config)
- // const renderedContent = Markdoc.renderers.html(children)
- // if (!attributes.id) {
- // attributes.id = slugify(renderedContent)
- // }
- // return new Tag(this.render, attributes, children)
- // },
- // },
- // blockquote: {
- // render: "Blockquote",
- // },
- // list: {
- // render: "List",
- // attributes: {
- // ordered: { type: Boolean, required: false },
- // },
- // },
- // inline: {},
- // table: { render: "Table" },
- // thead: { render: "TableHeader" },
- // th: { render: "TableHead" },
- // tr: { render: "TableRow" },
- // tbody: { render: "TableBody" },
- // td: { render: "TableCell" },
- // fence: {
- // render: "Code",
- // attributes: {
- // content: {
- // type: String,
- // },
- // language: {
- // type: String,
- // },
- // id: {
- // type: String,
- // required: false,
- // },
- // lineNumbers: {
- // type: Boolean,
- // required: false,
- // default: true,
- // },
- // fileName: {
- // type: String,
- // required: false,
- // },
- // },
- // },
- // },
- // tags: {
- // callout: {
- // render: "Callout",
- // attributes: {
- // title: {
- // type: String,
- // default: "default title",
- // },
- // type: {
- // type: String,
- // default: "default",
- // },
- // },
- // },
- // orderedlist: {
- // render: "List",
- // attributes: {
- // ordered: { type: Boolean, required: false, default: true },
- // type: { type: String, required: false },
- // start: { type: Number, required: false },
- // },
- // transform(node, config) {
- // const attributes = node.transformAttributes(config)
- // const children = node.transformChildren(config)
- // const elements = children[0] as any
- // if (children.length && elements?.name === "List") {
- // elements.attributes = attributes
- // }
- // return elements
- // },
- // },
- // tabs: {
- // render: "Tabs",
- // children: ["Tab"],
- // transform(node, config) {
- // const labels = node
- // .transformChildren(config)
- // .filter((child: any) => child && child.name === "Tab")
- // .map((tab: any) =>
- // typeof tab === "object" ? tab?.attributes?.label : null,
- // )
- // const defaultValue = (
- // node
- // .transformChildren(config)
- // .filter((child: any) => child && child.name === "Tab")
- // .find((tab: any) => tab?.attributes?.default == true) as any
- // )?.attributes?.label
- // return new Tag(
- // this.render,
- // { labels, defaultValue },
- // node.transformChildren(config),
- // )
- // },
- // },
- // tab: {
- // render: "Tab",
- // attributes: {
- // label: { type: String, required: true },
- // default: { type: Boolean, required: false },
- // },
- // },
- // accordion: {
- // render: "Accordion",
- // children: ["AccordionItem"],
- // attributes: {
- // type: { type: String },
- // collapsible: { type: Boolean, required: false, default: false },
- // },
- // },
- // accordionitem: {
- // render: "AccordionItem",
- // attributes: {
- // title: { type: String, required: true },
- // },
- // },
- // },
+ nodes: {
+ // paragraph: {
+ // render: "Paragraph",
+ // },
+ // link: {
+ // ...markdocNodes.link,
+ // render: "CustomLink",
+ // },
+ heading: headingConfig,
+ // blockquote: {
+ // render: "Blockquote",
+ // },
+ // list: {
+ // render: "List",
+ // attributes: {
+ // ordered: { type: Boolean, required: false },
+ // },
+ // },
+ // inline: {},
+ // table: { render: "Table" },
+ // thead: { render: "TableHeader" },
+ // th: { render: "TableHead" },
+ // tr: { render: "TableRow" },
+ // tbody: { render: "TableBody" },
+ // td: { render: "TableCell" },
+ // fence: {
+ // render: "Code",
+ // attributes: {
+ // content: {
+ // type: String,
+ // },
+ // language: {
+ // type: String,
+ // },
+ // id: {
+ // type: String,
+ // required: false,
+ // },
+ // lineNumbers: {
+ // type: Boolean,
+ // required: false,
+ // default: true,
+ // },
+ // fileName: {
+ // type: String,
+ // required: false,
+ // },
+ // },
+ // },
+ // },
+ // tags: {
+ // callout: {
+ // render: "Callout",
+ // attributes: {
+ // title: {
+ // type: String,
+ // default: "default title",
+ // },
+ // type: {
+ // type: String,
+ // default: "default",
+ // },
+ // },
+ // },
+ // orderedlist: {
+ // render: "List",
+ // attributes: {
+ // ordered: { type: Boolean, required: false, default: true },
+ // type: { type: String, required: false },
+ // start: { type: Number, required: false },
+ // },
+ // transform(node, config) {
+ // const attributes = node.transformAttributes(config)
+ // const children = node.transformChildren(config)
+ // const elements = children[0] as any
+ // if (children.length && elements?.name === "List") {
+ // elements.attributes = attributes
+ // }
+ // return elements
+ // },
+ // },
+ // tabs: {
+ // render: "Tabs",
+ // children: ["Tab"],
+ // transform(node, config) {
+ // const labels = node
+ // .transformChildren(config)
+ // .filter((child: any) => child && child.name === "Tab")
+ // .map((tab: any) =>
+ // typeof tab === "object" ? tab?.attributes?.label : null,
+ // )
+ // const defaultValue = (
+ // node
+ // .transformChildren(config)
+ // .filter((child: any) => child && child.name === "Tab")
+ // .find((tab: any) => tab?.attributes?.default == true) as any
+ // )?.attributes?.label
+ // return new Tag(
+ // this.render,
+ // { labels, defaultValue },
+ // node.transformChildren(config),
+ // )
+ // },
+ // },
+ // tab: {
+ // render: "Tab",
+ // attributes: {
+ // label: { type: String, required: true },
+ // default: { type: Boolean, required: false },
+ // },
+ // },
+ // accordion: {
+ // render: "Accordion",
+ // children: ["AccordionItem"],
+ // attributes: {
+ // type: { type: String },
+ // collapsible: { type: Boolean, required: false, default: false },
+ // },
+ // },
+ // accordionitem: {
+ // render: "AccordionItem",
+ // attributes: {
+ // title: { type: String, required: true },
+ // },
+ // },
+ },
};
const components = {
// Paragraph: TypographyP,
- // Heading: Heading,
+ Heading: Heading,
// Blockquote: TypographyBlockquote,
// Callout: Callout,
// List: TypographyList,
diff --git a/packages/markdoc-heading/index.ts b/packages/markdoc-heading/index.ts
index 8879d7a..a354859 100644
--- a/packages/markdoc-heading/index.ts
+++ b/packages/markdoc-heading/index.ts
@@ -1 +1,2 @@
-export * from './src';
\ No newline at end of file
+export { config } from "./src/config";
+export { Heading } from "./src/Heading";
diff --git a/packages/markdoc-heading/package.json b/packages/markdoc-heading/package.json
index 548d60a..6e345bb 100644
--- a/packages/markdoc-heading/package.json
+++ b/packages/markdoc-heading/package.json
@@ -19,6 +19,12 @@
"format": "prettier --check . --ignore-path ../../.gitignore",
"typecheck": "tsc --noEmit"
},
+ "dependencies": {
+ "@markdoc/markdoc": "0.4.0",
+ "@sindresorhus/slugify": "2.2.1",
+ "@acme/helpers": "workspace:0.1.0",
+ "react": "18.2.0"
+ },
"devDependencies": {
"@acme/eslint-config": "workspace:0.2.0",
"@acme/prettier-config": "workspace:0.1.0",
diff --git a/packages/markdoc-heading/src/Heading.tsx b/packages/markdoc-heading/src/Heading.tsx
new file mode 100644
index 0000000..8fab69c
--- /dev/null
+++ b/packages/markdoc-heading/src/Heading.tsx
@@ -0,0 +1,47 @@
+import type { ReactNode } from "react";
+
+import { cn } from "@acme/helpers";
+
+/**
+ * Source: https://github.com/dylanmeivis/nextjs13-starter-markdoc
+ */
+
+interface HeadingProps {
+ children: ReactNode;
+ level: number;
+ id: string;
+}
+
+export function Heading({ children, level, id }: HeadingProps) {
+ let headingClass = "text-base font-semibold";
+
+ switch (level) {
+ case 1:
+ headingClass = "text-4xl font-extrabold lg:text-5xl";
+ break;
+ case 2:
+ headingClass =
+ "border-b pb-2 text-3xl font-semibold transition-colors first:mt-0";
+ break;
+ case 3:
+ headingClass = "text-2xl font-semibold";
+ break;
+ case 4:
+ headingClass = "text-xl font-semibold";
+ break;
+ case 5:
+ headingClass = "text-lg font-semibold";
+ break;
+ }
+
+ const HeadingTag = `h${level}` as keyof JSX.IntrinsicElements;
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/packages/markdoc-heading/src/config.ts b/packages/markdoc-heading/src/config.ts
new file mode 100644
index 0000000..c76ede4
--- /dev/null
+++ b/packages/markdoc-heading/src/config.ts
@@ -0,0 +1,22 @@
+import Markdoc, { Tag } from "@markdoc/markdoc";
+import type { Schema } from "@markdoc/markdoc";
+import { slugifyWithCounter } from "@sindresorhus/slugify";
+
+const slugify = slugifyWithCounter();
+
+export const config: Schema = {
+ render: "Heading",
+ attributes: {
+ id: { type: String },
+ level: { type: Number, required: true },
+ },
+ transform(node, config) {
+ const attributes = node.transformAttributes(config);
+ const children = node.transformChildren(config);
+ const renderedContent = Markdoc.renderers.html(children);
+ if (!attributes.id) {
+ attributes.id = slugify(renderedContent);
+ }
+ return new Tag(this.render, attributes, children);
+ },
+};
diff --git a/packages/markdoc-heading/src/index.ts b/packages/markdoc-heading/src/index.ts
deleted file mode 100644
index 14a82c7..0000000
--- a/packages/markdoc-heading/src/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export const name = 'markdoc-heading';
\ No newline at end of file
diff --git a/packages/ui/index.ts b/packages/ui/index.ts
index 8879d7a..4d902f6 100644
--- a/packages/ui/index.ts
+++ b/packages/ui/index.ts
@@ -1 +1,2 @@
-export * from './src';
\ No newline at end of file
+export * from "./src";
+export { cn } from "../helpers/src/cn";
diff --git a/packages/ui/package.json b/packages/ui/package.json
index 910036c..679bcbc 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -23,10 +23,14 @@
"class-variance-authority": "^0.7.0",
"clsx": "2.0.0",
"lucide-react": "^0.294.0",
+ "tailwindcss": "3.3.6",
"tailwind-merge": "2.1.0",
- "tailwindcss-animate": "1.0.7"
+ "tailwindcss-animate": "1.0.7",
+ "@acme/tailwind-config": "workspace:0.1.0",
+ "@acme/helpers": "workspace:0.1.0"
},
"devDependencies": {
+ "@acme/markdoc-base": "workspace:0.1.0",
"@acme/eslint-config": "workspace:0.2.0",
"@acme/prettier-config": "workspace:0.1.0",
"@acme/tsconfig": "workspace:0.1.0",
diff --git a/packages/ui/src/components/table-of-contents.tsx b/packages/ui/src/components/table-of-contents.tsx
new file mode 100644
index 0000000..b726196
--- /dev/null
+++ b/packages/ui/src/components/table-of-contents.tsx
@@ -0,0 +1,104 @@
+// Source: https://github.com/shadcn/ui/blob/main/apps/www/components/toc.tsx
+"use client";
+
+import * as React from "react";
+
+import { cn } from "@acme/helpers";
+import type { TableOfContents } from "@acme/markdoc-base";
+
+interface TocProps {
+ toc: TableOfContents[];
+}
+
+interface TreeProps {
+ tree: TableOfContents[];
+ level?: number;
+ activeItem?: string;
+}
+
+export function TableOfContents({ toc }: TocProps) {
+ const itemIds = React.useMemo(
+ () =>
+ toc
+ ? toc
+ .flatMap((item) => [
+ `#${item.id}`,
+ ...(item?.children?.map((item) => `#${item.id}`) ?? ""),
+ ])
+ .flat()
+ .filter((ele) => ele !== "")
+ .map((id) => id.split("#")[1]!)
+ : [],
+ [toc],
+ );
+
+ const activeHeading = useActiveItem(itemIds);
+
+ return ;
+}
+
+function useActiveItem(itemIds: string[]) {
+ const [activeId, setActiveId] = React.useState("");
+
+ React.useEffect(() => {
+ const observer = new IntersectionObserver(
+ (entries) => {
+ entries.forEach((entry) => {
+ if (entry.isIntersecting) {
+ setActiveId(entry.target.id);
+ }
+ });
+ },
+ { rootMargin: `0% 0% -80% 0%` },
+ );
+
+ itemIds?.forEach((id) => {
+ const element = document.getElementById(id);
+ if (element) {
+ observer.observe(element);
+ }
+ });
+
+ return () => {
+ itemIds?.forEach((id) => {
+ const element = document.getElementById(id);
+ if (element) {
+ observer.unobserve(element);
+ }
+ });
+ };
+ }, [itemIds]);
+
+ return activeId;
+}
+
+function Tree({ tree, level = 1, activeItem }: TreeProps) {
+ return tree?.length ? (
+
+ {tree.map((item, index) => {
+ return (
+ -
+
+ {item.title}
+
+ {item.children && item.children?.length > 0 && level < 3 ? (
+
+ ) : null}
+
+ );
+ })}
+
+ ) : null;
+}
diff --git a/packages/ui/tailwind.config.js b/packages/ui/tailwind.config.js
deleted file mode 100644
index 0377ea1..0000000
--- a/packages/ui/tailwind.config.js
+++ /dev/null
@@ -1,76 +0,0 @@
-/** @type {import('tailwindcss').Config} */
-module.exports = {
- darkMode: ["class"],
- content: [
- './pages/**/*.{ts,tsx}',
- './components/**/*.{ts,tsx}',
- './app/**/*.{ts,tsx}',
- './src/**/*.{ts,tsx}',
- ],
- theme: {
- container: {
- center: true,
- padding: "2rem",
- screens: {
- "2xl": "1400px",
- },
- },
- extend: {
- colors: {
- border: "hsl(var(--border))",
- input: "hsl(var(--input))",
- ring: "hsl(var(--ring))",
- background: "hsl(var(--background))",
- foreground: "hsl(var(--foreground))",
- primary: {
- DEFAULT: "hsl(var(--primary))",
- foreground: "hsl(var(--primary-foreground))",
- },
- secondary: {
- DEFAULT: "hsl(var(--secondary))",
- foreground: "hsl(var(--secondary-foreground))",
- },
- destructive: {
- DEFAULT: "hsl(var(--destructive))",
- foreground: "hsl(var(--destructive-foreground))",
- },
- muted: {
- DEFAULT: "hsl(var(--muted))",
- foreground: "hsl(var(--muted-foreground))",
- },
- accent: {
- DEFAULT: "hsl(var(--accent))",
- foreground: "hsl(var(--accent-foreground))",
- },
- popover: {
- DEFAULT: "hsl(var(--popover))",
- foreground: "hsl(var(--popover-foreground))",
- },
- card: {
- DEFAULT: "hsl(var(--card))",
- foreground: "hsl(var(--card-foreground))",
- },
- },
- borderRadius: {
- lg: "var(--radius)",
- md: "calc(var(--radius) - 2px)",
- sm: "calc(var(--radius) - 4px)",
- },
- keyframes: {
- "accordion-down": {
- from: { height: 0 },
- to: { height: "var(--radix-accordion-content-height)" },
- },
- "accordion-up": {
- from: { height: "var(--radix-accordion-content-height)" },
- to: { height: 0 },
- },
- },
- animation: {
- "accordion-down": "accordion-down 0.2s ease-out",
- "accordion-up": "accordion-up 0.2s ease-out",
- },
- },
- },
- plugins: [require("tailwindcss-animate")],
-}
\ No newline at end of file
diff --git a/packages/ui/tailwind.config.ts b/packages/ui/tailwind.config.ts
new file mode 100644
index 0000000..5906f1b
--- /dev/null
+++ b/packages/ui/tailwind.config.ts
@@ -0,0 +1,8 @@
+import type { Config } from "tailwindcss"
+
+import baseConfig from "@acme/tailwind-config"
+
+export default {
+ content: ["./src/**/*.{ts,tsx}"],
+ presets: [baseConfig],
+} satisfies Config
diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json
index 27b5382..002703b 100644
--- a/packages/ui/tsconfig.json
+++ b/packages/ui/tsconfig.json
@@ -7,6 +7,6 @@
"@/*": ["./src/*"]
}
},
- "include": ["*.ts", "src"],
+ "include": ["*.ts", "src", "../helpers/src/lib", "../helpers/src/cn.ts"],
"exclude": ["node_modules"]
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index fb55d5f..52dd2f6 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -85,6 +85,34 @@ importers:
specifier: 5.3.3
version: 5.3.3
+ packages/helpers:
+ dependencies:
+ clsx:
+ specifier: 2.0.0
+ version: 2.0.0
+ tailwind-merge:
+ specifier: 2.1.0
+ version: 2.1.0
+ tailwindcss:
+ specifier: 3.3.6
+ version: 3.3.6
+ devDependencies:
+ '@acme/eslint-config':
+ specifier: workspace:0.2.0
+ version: link:../../tooling/eslint
+ '@acme/prettier-config':
+ specifier: workspace:0.1.0
+ version: link:../../tooling/prettier
+ '@acme/tsconfig':
+ specifier: workspace:0.1.0
+ version: link:../../tooling/typescript
+ eslint:
+ specifier: 8.55.0
+ version: 8.55.0
+ typescript:
+ specifier: 5.3.3
+ version: 5.3.3
+
packages/markdoc-accordion:
devDependencies:
'@acme/eslint-config':
@@ -105,9 +133,24 @@ importers:
packages/markdoc-base:
dependencies:
+ '@acme/helpers':
+ specifier: workspace:0.1.0
+ version: link:../helpers
+ '@acme/markdoc-heading':
+ specifier: workspace:0.1.0
+ version: link:../markdoc-heading
'@markdoc/markdoc':
specifier: 0.4.0
- version: 0.4.0
+ version: 0.4.0(react@18.2.0)
+ string-strip-html:
+ specifier: 13.4.3
+ version: 13.4.3
+ zod:
+ specifier: 3.22.4
+ version: 3.22.4
+ zod-matter:
+ specifier: 0.1.1
+ version: 0.1.1(gray-matter@4.0.3)(zod@3.22.4)
devDependencies:
'@acme/eslint-config':
specifier: workspace:0.2.0
@@ -180,6 +223,19 @@ importers:
version: 5.3.3
packages/markdoc-heading:
+ dependencies:
+ '@acme/helpers':
+ specifier: workspace:0.1.0
+ version: link:../helpers
+ '@markdoc/markdoc':
+ specifier: 0.4.0
+ version: 0.4.0(react@18.2.0)
+ '@sindresorhus/slugify':
+ specifier: 2.2.1
+ version: 2.2.1
+ react:
+ specifier: 18.2.0
+ version: 18.2.0
devDependencies:
'@acme/eslint-config':
specifier: workspace:0.2.0
@@ -217,6 +273,12 @@ importers:
packages/ui:
dependencies:
+ '@acme/helpers':
+ specifier: workspace:0.1.0
+ version: link:../helpers
+ '@acme/tailwind-config':
+ specifier: workspace:0.1.0
+ version: link:../../tooling/tailwind
class-variance-authority:
specifier: ^0.7.0
version: 0.7.0
@@ -229,6 +291,9 @@ importers:
tailwind-merge:
specifier: 2.1.0
version: 2.1.0
+ tailwindcss:
+ specifier: 3.3.6
+ version: 3.3.6
tailwindcss-animate:
specifier: 1.0.7
version: 1.0.7(tailwindcss@3.3.6)
@@ -236,6 +301,9 @@ importers:
'@acme/eslint-config':
specifier: workspace:0.2.0
version: link:../../tooling/eslint
+ '@acme/markdoc-base':
+ specifier: workspace:0.1.0
+ version: link:../markdoc-base
'@acme/prettier-config':
specifier: workspace:0.1.0
version: link:../../tooling/prettier
@@ -682,7 +750,7 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.15
dev: true
- /@markdoc/markdoc@0.4.0:
+ /@markdoc/markdoc@0.4.0(react@18.2.0):
resolution: {integrity: sha512-fSh4P3Y4E7oaKYc2oNzSIJVPDto7SMzAuQN1Iyx53UxzleA6QzRdNWRxmiPqtVDaDi5dELd2yICoG91csrGrAw==}
engines: {node: '>=14.7.0'}
peerDependencies:
@@ -693,6 +761,8 @@ packages:
optional: true
react:
optional: true
+ dependencies:
+ react: 18.2.0
optionalDependencies:
'@types/markdown-it': 12.2.3
dev: false
@@ -806,6 +876,21 @@ packages:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.15.0
+ /@sindresorhus/slugify@2.2.1:
+ resolution: {integrity: sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==}
+ engines: {node: '>=12'}
+ dependencies:
+ '@sindresorhus/transliterate': 1.6.0
+ escape-string-regexp: 5.0.0
+ dev: false
+
+ /@sindresorhus/transliterate@1.6.0:
+ resolution: {integrity: sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ escape-string-regexp: 5.0.0
+ dev: false
+
/@swc/helpers@0.5.2:
resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==}
dependencies:
@@ -938,6 +1023,16 @@ packages:
dev: false
optional: true
+ /@types/lodash-es@4.17.12:
+ resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
+ dependencies:
+ '@types/lodash': 4.14.202
+ dev: false
+
+ /@types/lodash@4.14.202:
+ resolution: {integrity: sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==}
+ dev: false
+
/@types/markdown-it@12.2.3:
resolution: {integrity: sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==}
requiresBuild: true
@@ -1215,6 +1310,12 @@ packages:
/arg@5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
+ /argparse@1.0.10:
+ resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
+ dependencies:
+ sprintf-js: 1.0.3
+ dev: false
+
/argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
@@ -1555,6 +1656,13 @@ packages:
engines: {node: '>=6'}
dev: false
+ /codsen-utils@1.6.2:
+ resolution: {integrity: sha512-L+Cn6c/q0m3nHT6inNIKO1E+BHzeJ1b6McBQLcHvq46gYt7RSPEjYqmq0P5LWZsz+hb+w0tS5WkH6hRvZeHz2A==}
+ engines: {node: '>=14.18.0'}
+ dependencies:
+ rfdc: 1.3.0
+ dev: false
+
/color-convert@1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
dependencies:
@@ -1886,6 +1994,11 @@ packages:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
+ /escape-string-regexp@5.0.0:
+ resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
+ engines: {node: '>=12'}
+ dev: false
+
/escodegen@2.1.0:
resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==}
engines: {node: '>=6.0'}
@@ -2127,7 +2240,6 @@ packages:
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
engines: {node: '>=4'}
hasBin: true
- dev: true
/esquery@1.5.0:
resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
@@ -2164,6 +2276,13 @@ packages:
strip-final-newline: 2.0.0
dev: true
+ /extend-shallow@2.0.1:
+ resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-extendable: 0.1.1
+ dev: false
+
/external-editor@3.1.0:
resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
engines: {node: '>=4'}
@@ -2439,6 +2558,16 @@ packages:
/graphemer@1.4.0:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+ /gray-matter@4.0.3:
+ resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==}
+ engines: {node: '>=6.0'}
+ dependencies:
+ js-yaml: 3.14.1
+ kind-of: 6.0.3
+ section-matter: 1.0.0
+ strip-bom-string: 1.0.0
+ dev: false
+
/handlebars@4.7.8:
resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==}
engines: {node: '>=0.4.7'}
@@ -2500,6 +2629,10 @@ packages:
upper-case: 1.1.3
dev: true
+ /html-entities@2.4.0:
+ resolution: {integrity: sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==}
+ dev: false
+
/http-proxy-agent@7.0.0:
resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==}
engines: {node: '>= 14'}
@@ -2678,6 +2811,11 @@ packages:
has-tostringtag: 1.0.0
dev: false
+ /is-extendable@0.1.1:
+ resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
/is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
@@ -2848,6 +2986,14 @@ packages:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
dev: false
+ /js-yaml@3.14.1:
+ resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
+ hasBin: true
+ dependencies:
+ argparse: 1.0.10
+ esprima: 4.0.1
+ dev: false
+
/js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
@@ -2911,6 +3057,11 @@ packages:
dependencies:
json-buffer: 3.0.1
+ /kind-of@6.0.3:
+ resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
/language-subtag-registry@0.3.22:
resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==}
dev: false
@@ -2946,6 +3097,10 @@ packages:
dependencies:
p-locate: 5.0.0
+ /lodash-es@4.17.21:
+ resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
+ dev: false
+
/lodash.get@4.4.2:
resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
dev: true
@@ -3577,6 +3732,37 @@ packages:
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+ /ranges-apply@7.0.12:
+ resolution: {integrity: sha512-RsdQnaC0pU+KV69muxE47NMhLCz9XHj3aAL/ykBtUXhtFWaq2/KXWM0wVXCYkBD/lIQRU1ZJhBla4LZPH2ywRQ==}
+ engines: {node: '>=14.18.0'}
+ dependencies:
+ ranges-merge: 9.0.12
+ tiny-invariant: 1.3.1
+ dev: false
+
+ /ranges-merge@9.0.12:
+ resolution: {integrity: sha512-Asg92aN9sZebnKu79bAlmU+kcHL9hcQZJ4q1WLX2h65ydKfAVtHZp3KhOT4eBCb+G7cSCHUSSK0hqzd/p02ydA==}
+ engines: {node: '>=14.18.0'}
+ dependencies:
+ ranges-push: 7.0.12
+ ranges-sort: 6.0.10
+ dev: false
+
+ /ranges-push@7.0.12:
+ resolution: {integrity: sha512-Jwr/rCIAitwuT+dodq9ISZa09WWWua/mRud4OXPiwA+D7GxObsGgsSkf/v62h6zDxGPJkCuEpryKoOg90sbU6A==}
+ engines: {node: '>=14.18.0'}
+ dependencies:
+ codsen-utils: 1.6.2
+ ranges-sort: 6.0.10
+ string-collapse-leading-whitespace: 7.0.6
+ string-trim-spaces-only: 5.0.9
+ dev: false
+
+ /ranges-sort@6.0.10:
+ resolution: {integrity: sha512-Tts5PiQQW+M8jMIkE/y0VdF5+GYFlv85qYAfQUBtekORbNn+7IVD+wPLJZ3LmfJSFJz/Jm3Wlgz+OpAeeHr5PA==}
+ engines: {node: '>=14.18.0'}
+ dev: false
+
/rc@1.2.8:
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
hasBin: true
@@ -3699,6 +3885,10 @@ packages:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+ /rfdc@1.3.0:
+ resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==}
+ dev: false
+
/rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
hasBin: true
@@ -3760,6 +3950,14 @@ packages:
loose-envify: 1.4.0
dev: false
+ /section-matter@1.0.0:
+ resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==}
+ engines: {node: '>=4'}
+ dependencies:
+ extend-shallow: 2.0.1
+ kind-of: 6.0.3
+ dev: false
+
/semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
@@ -3923,11 +4121,46 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
+ /sprintf-js@1.0.3:
+ resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
+ dev: false
+
/streamsearch@1.1.0:
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
engines: {node: '>=10.0.0'}
dev: false
+ /string-collapse-leading-whitespace@7.0.6:
+ resolution: {integrity: sha512-FqOnt9H0+eeXukBb3Js2qPLLI0T5ebp96TfU0+AwoAuQQidETeoRMYJG6mUYebP4SBYZkap+HbAK6U/wGWxJvA==}
+ engines: {node: '>=14.18.0'}
+ dev: false
+
+ /string-left-right@6.0.15:
+ resolution: {integrity: sha512-f80yIZCFZJnZcnCp8/Mk9zYRs210LHCkpNy668wusUzuh6qhryLA/SfxbFayxnFN12xdPARAvObu/wzYKX57wA==}
+ engines: {node: '>=14.18.0'}
+ dependencies:
+ codsen-utils: 1.6.2
+ rfdc: 1.3.0
+ dev: false
+
+ /string-strip-html@13.4.3:
+ resolution: {integrity: sha512-9ketPUGy6MWmHy5tZuy1LSXcEB690MCQ0eTvUlunCjCGGTIUjboHyFa/PADndYHlfvHDcdO9iwzqjheXI/K/jw==}
+ engines: {node: '>=14.18.0'}
+ dependencies:
+ '@types/lodash-es': 4.17.12
+ codsen-utils: 1.6.2
+ html-entities: 2.4.0
+ lodash-es: 4.17.21
+ ranges-apply: 7.0.12
+ ranges-push: 7.0.12
+ string-left-right: 6.0.15
+ dev: false
+
+ /string-trim-spaces-only@5.0.9:
+ resolution: {integrity: sha512-Yl/Ot+1YksCi2PI+I4nw6Mq2U2QV7vsCWFT+1lfWoFGYVS/27JmtWvueYiQW0YTPX4xz4DhV2cQijDakIPTWGg==}
+ engines: {node: '>=14.18.0'}
+ dev: false
+
/string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
@@ -3988,6 +4221,11 @@ packages:
dependencies:
ansi-regex: 5.0.1
+ /strip-bom-string@1.0.0:
+ resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
/strip-bom@3.0.0:
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
engines: {node: '>=4'}
@@ -4122,6 +4360,10 @@ packages:
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
dev: true
+ /tiny-invariant@1.3.1:
+ resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==}
+ dev: false
+
/tinycolor2@1.6.0:
resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
dev: true
@@ -4518,6 +4760,17 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
+ /zod-matter@0.1.1(gray-matter@4.0.3)(zod@3.22.4):
+ resolution: {integrity: sha512-+GGjzfWhlFtzok6eV5YR7AS3mDYAFgxwX40B5tqfU00ij/gWpBsXy0qQcFkTxFKMiaGYwkMLpS0ckTWe56Qjsg==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ gray-matter: '>=3.0.0'
+ zod: '>=3.0.0'
+ dependencies:
+ gray-matter: 4.0.3
+ zod: 3.22.4
+ dev: false
+
/zod@3.22.4:
resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
dev: false