Skip to content
This repository has been archived by the owner on Sep 8, 2024. It is now read-only.

Commit

Permalink
configure markdoc nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
noxify committed Dec 11, 2023
1 parent c0023ec commit aefb06f
Show file tree
Hide file tree
Showing 25 changed files with 807 additions and 250 deletions.
2 changes: 1 addition & 1 deletion apps/nextjs/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
17 changes: 0 additions & 17 deletions apps/nextjs/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) {
Expand Down
18 changes: 15 additions & 3 deletions apps/nextjs/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<main className="flex h-screen flex-col items-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
Hello World
{Markdoc.renderers.react(pageContent.content, React, components)}
</main>
)
);
}
47 changes: 47 additions & 0 deletions apps/nextjs/src/content/test.md
Original file line number Diff line number Diff line change
@@ -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!
1 change: 1 addition & 0 deletions packages/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { cn } from "./src/cn";
40 changes: 40 additions & 0 deletions packages/helpers/package.json
Original file line number Diff line number Diff line change
@@ -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"
}
File renamed without changes.
8 changes: 8 additions & 0 deletions packages/helpers/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "@acme/tsconfig/base.json",
"compilerOptions": {
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
},
"include": ["*.ts", "src"],
"exclude": ["node_modules"]
}
4 changes: 2 additions & 2 deletions packages/markdoc-base/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import Markdoc from "@markdoc/markdoc";

import { components, config } from "./src";



export { Markdoc, config, components };

export * from "./src/helpers";
7 changes: 6 additions & 1 deletion packages/markdoc-base/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
13 changes: 13 additions & 0 deletions packages/markdoc-base/src/frontmatter.ts
Original file line number Diff line number Diff line change
@@ -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;
}
92 changes: 92 additions & 0 deletions packages/markdoc-base/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -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;
}
Loading

0 comments on commit aefb06f

Please sign in to comment.