Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions app/routes.res
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ let blogArticleRoutes =
route(path, "./routes/BlogArticleRoute.jsx", ~options={id: path})
)

let docsReactRoutes =
MdxFile.scanPaths(~dir="markdown-pages/docs/react", ~alias="docs/react")->Array.map(path =>
route(path, "./routes/DocsReactRoute.jsx", ~options={id: path})
)

let communityRoutes =
MdxFile.scanPaths(~dir="markdown-pages/community", ~alias="community")->Array.map(path =>
route(path, "./routes/CommunityRoute.jsx", ~options={id: path})
Expand All @@ -58,11 +63,11 @@ let mdxRoutes = mdxRoutes("./routes/MdxRoute.jsx")->Array.filter(r =>
->Option.map(path =>
path === "blog" ||
String.startsWith(path, "blog/") ||
path === "docs/react" ||
String.startsWith(path, "docs/react/") ||
path === "community" ||
String.startsWith(path, "community/") ||
path === "docs/manual/api" ||
path === "community" ||
String.startsWith(path, "community/")
path === "docs/manual/api"
)
->Option.getOr(false)
)
Expand All @@ -85,6 +90,7 @@ let default = [
...beltRoutes,
...domRoutes,
...blogArticleRoutes,
...docsReactRoutes,
...communityRoutes,
...mdxRoutes,
route("*", "./routes/NotFoundRoute.jsx"),
Expand Down
171 changes: 171 additions & 0 deletions app/routes/DocsReactRoute.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
type loaderData = {
compiledMdx: CompiledMdx.t,
categories: array<SidebarLayout.Sidebar.Category.t>,
entries: array<TableOfContents.entry>,
title: string,
description: string,
filePath: string,
}

let convertToNavItems = (items, rootPath) =>
Array.map(items, (item): SidebarLayout.Sidebar.NavItem.t => {
let href = switch item.Mdx.slug {
| Some(slug) => `${rootPath}/${slug}`
| None => rootPath
}
{
name: item.title,
href,
}
})

let getGroup = (groups, groupName): SidebarLayout.Sidebar.Category.t => {
{
name: groupName,
items: groups
->Dict.get(groupName)
->Option.getOr([]),
}
}

let getAllGroups = (groups, groupNames): array<SidebarLayout.Sidebar.Category.t> =>
groupNames->Array.map(item => getGroup(groups, item))

// Build sidebar categories from all React docs, sorted by their "order" field in frontmatter
let reactTableOfContents = async () => {
let groups =
(await Mdx.allMdx(~filterByPaths=["markdown-pages/docs"]))
->Mdx.filterMdxPages("docs/react")
->Mdx.groupBySection
->Dict.mapValues(values => values->Mdx.sortSection->convertToNavItems("/docs/react"))

getAllGroups(groups, ["Overview", "Main Concepts", "Hooks & State Management", "Guides"])
}

let loader: ReactRouter.Loader.t<loaderData> = async ({request}) => {
let {pathname} = WebAPI.URL.make(~url=request.url)
let filePath = MdxFile.resolveFilePath(
(pathname :> string),
~dir="markdown-pages/docs/react",
~alias="docs/react",
)

let raw = await Node.Fs.readFile(filePath, "utf-8")
let {frontmatter}: MarkdownParser.result = MarkdownParser.parseSync(raw)

let description = switch frontmatter {
| Object(dict) =>
switch dict->Dict.get("description") {
| Some(String(s)) => s
| _ => ""
}
| _ => ""
}

let title = switch frontmatter {
| Object(dict) =>
switch dict->Dict.get("title") {
| Some(String(s)) => s
| _ => ""
}
| _ => ""
}

let categories = await reactTableOfContents()

let compiledMdx = await MdxFile.compileMdx(raw, ~filePath, ~remarkPlugins=Mdx.plugins)

// Build table of contents entries from markdown headings
let markdownTree = Mdast.fromMarkdown(raw)
let tocResult = Mdast.toc(markdownTree, {maxDepth: 2})

let headers = Dict.make()
Mdast.reduceHeaders(tocResult.map, headers)

let entries =
headers
->Dict.toArray
->Array.map(((header, url)): TableOfContents.entry => {
header,
href: (url :> string),
})
->Array.slice(~start=2) // skip document entry and H1 title, keep h2 sections

{
compiledMdx,
categories,
entries,
title: `${title} | ReScript React`,
description,
filePath,
}
}

let default = () => {
let {pathname} = ReactRouter.useLocation()
let {compiledMdx, categories, entries, title, description, filePath} = ReactRouter.useLoaderData()

let breadcrumbs = list{
{Url.name: "Docs", href: "/docs/react/introduction"},
{
Url.name: "rescript-react",
href: "/docs/react/introduction",
},
}

let editHref = `https://github.com/rescript-lang/rescript-lang.org/blob/master/${filePath}`

let sidebarContent =
<aside className="px-4 w-full block">
<div className="flex justify-between items-baseline">
<div className="flex flex-col text-fire font-medium">
<VersionSelect />
</div>
<button
className="flex items-center" onClick={_ => NavbarUtils.closeMobileTertiaryDrawer()}
>
<Icon.Close />
</button>
</div>
<div className="mb-56">
{categories
->Array.map(category => {
let isItemActive = (navItem: SidebarLayout.Sidebar.NavItem.t) =>
navItem.href === (pathname :> string)
let getActiveToc = (navItem: SidebarLayout.Sidebar.NavItem.t) =>
if navItem.href === (pathname :> string) {
Some({TableOfContents.title, entries})
} else {
None
}
<div key=category.name>
<SidebarLayout.Sidebar.Category
isItemActive
getActiveToc
category
onClick={_ => NavbarUtils.closeMobileTertiaryDrawer()}
/>
</div>
})
->React.array}
</div>
</aside>

<>
<Meta title description />
<NavbarSecondary />
<NavbarTertiary sidebar=sidebarContent>
<SidebarLayout.BreadCrumbs crumbs=breadcrumbs />
<a
href=editHref className="inline text-14 hover:underline text-fire" rel="noopener noreferrer"
>
{React.string("Edit")}
</a>
</NavbarTertiary>
<DocsLayout categories activeToc={title, entries}>
<div className="markdown-body">
<MdxContent compiledMdx />
</div>
</DocsLayout>
</>
}
12 changes: 12 additions & 0 deletions app/routes/DocsReactRoute.resi
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
type loaderData = {
compiledMdx: CompiledMdx.t,
categories: array<SidebarLayout.Sidebar.Category.t>,
entries: array<TableOfContents.entry>,
title: string,
description: string,
filePath: string,
}

let loader: ReactRouter.Loader.t<loaderData>

let default: unit => React.element
35 changes: 2 additions & 33 deletions app/routes/MdxRoute.res
Original file line number Diff line number Diff line change
Expand Up @@ -99,22 +99,6 @@ let manualTableOfContents = async () => {
categories
}

let reactTableOfContents = async () => {
let groups =
(await allMdx(~filterByPaths=["markdown-pages/docs"]))
->filterMdxPages("docs/react")
->groupBySection
->Dict.mapValues(values => values->sortSection->convertToNavItems("/docs/react"))

// these are the categories that appear in the sidebar
let categories: array<SidebarLayout.Sidebar.Category.t> = getAllGroups(
groups,
["Overview", "Main Concepts", "Hooks & State Management", "Guides"],
)

categories
}

let loader: ReactRouter.Loader.t<loaderData> = async ({request}) => {
let {pathname} = WebAPI.URL.make(~url=request.url)

Expand Down Expand Up @@ -148,8 +132,6 @@ let loader: ReactRouter.Loader.t<loaderData> = async ({request}) => {
let categories = {
if pathname->String.includes("docs/manual") {
await manualTableOfContents()
} else if pathname->String.includes("docs/react") {
await reactTableOfContents()
} else {
[]
}
Expand Down Expand Up @@ -205,21 +187,11 @@ let loader: ReactRouter.Loader.t<loaderData> = async ({request}) => {
href: "/docs/manual/" ++ "introduction",
},
})
: pathname->String.includes("docs/react")
? Some(list{
{Url.name: "Docs", href: "/docs/"},
{
Url.name: "rescript-react",
href: "/docs/react/" ++ "introduction",
},
})
: None

let metaTitleCategory = {
let path = (pathname :> string)
let title = if path->String.includes("docs/react") {
"ReScript React"
} else if path->String.includes("docs/manual") {
let title = if path->String.includes("docs/manual") {
"ReScript Language Manual"
} else {
"ReScript"
Expand Down Expand Up @@ -255,8 +227,7 @@ let default = () => {
<>
{if (
(pathname :> string)->String.includes("docs/manual") ||
(pathname :> string)->String.includes("docs/react") ||
(pathname :> string)->String.includes("docs/guidelines")
(pathname :> string)->String.includes("docs/guidelines")
) {
<>
<Meta title=title description={attributes.description->Nullable.getOr("")} />
Expand All @@ -267,8 +238,6 @@ let default = () => {
if index === 0 {
if (pathname :> string)->String.includes("docs/manual") {
{...item, href: "/docs/manual/introduction"}
} else if (pathname :> string)->String.includes("docs/react") {
{...item, href: "/docs/react/introduction"}
} else {
item
}
Expand Down
4 changes: 3 additions & 1 deletion src/Mdx.res
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ let sortSection = mdxPages =>
Array.toSorted(mdxPages, (a: attributes, b: attributes) =>
switch (a.order, b.order) {
| (Some(a), Some(b)) => a > b ? 1.0 : -1.0
| _ => -1.0
| (Some(_), None) => -1.0
| (None, Some(_)) => 1.0
| (None, None) => 0.0
}
)

Expand Down
Loading