Skip to content
Open
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
40 changes: 0 additions & 40 deletions .yarn/patches/react-router-mdx-npm-1.0.8-d4402c3003.patch

This file was deleted.

6 changes: 6 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,12 @@ let default: unit => React.element
- **Lefthook** runs `yarn format` on pre-commit (auto-stages fixed files).
- Generated `.mjs`/`.jsx` output files from ReScript are git-tracked but excluded from Prettier.

## Pull Requests and Commits

- Use conventional commits format for commit messages (e.g. `feat: add new API docs`, `fix: resolve loader data issue`).
- Commit bodies should explain what changed with some concise details
- PR descriptions should provide context for the change, a summary of the changes with descriptions, and reference any related issues.

## Important Warnings

- Do **not** modify generated `.jsx` / `.mjs` files directly — they are ReScript compiler output.
Expand Down
38 changes: 23 additions & 15 deletions app/routes.res
Original file line number Diff line number Diff line change
Expand Up @@ -47,26 +47,31 @@ let blogArticleRoutes =
route(path, "./routes/BlogArticleRoute.jsx", ~options={id: path})
)

let docsManualRoutes =
MdxFile.scanPaths(~dir="markdown-pages/docs/manual", ~alias="docs/manual")
->Array.filter(path => !String.includes(path, "docs/manual/api"))
->Array.map(path => route(path, "./routes/DocsManualRoute.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 docsGuidelinesRoutes =
MdxFile.scanPaths(
~dir="markdown-pages/docs/guidelines",
~alias="docs/guidelines",
)->Array.map(path => route(path, "./routes/DocsGuidelinesRoute.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})
)

let mdxRoutes = mdxRoutes("./routes/MdxRoute.jsx")->Array.filter(r =>
!(
r.path
->Option.map(path =>
path === "blog" ||
String.startsWith(path, "blog/") ||
path === "community" ||
String.startsWith(path, "community/") ||
path === "docs/manual/api" ||
path === "community" ||
String.startsWith(path, "community/")
)
->Option.getOr(false)
let syntaxLookupDetailRoutes =
MdxFile.scanPaths(~dir="markdown-pages/syntax-lookup", ~alias="syntax-lookup")->Array.map(path =>
route(path, "./routes/SyntaxLookupDetailRoute.jsx", ~options={id: path})
)
)

let default = [
index("./routes/LandingPageRoute.jsx"),
Expand All @@ -85,7 +90,10 @@ let default = [
...beltRoutes,
...domRoutes,
...blogArticleRoutes,
...docsManualRoutes,
...docsReactRoutes,
...docsGuidelinesRoutes,
...communityRoutes,
...mdxRoutes,
...syntaxLookupDetailRoutes,
route("*", "./routes/NotFoundRoute.jsx"),
]
10 changes: 9 additions & 1 deletion app/routes.resi
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
let stdlibPaths: array<string>
let domPaths: array<string>
let beltPaths: array<string>
let stdlibRoutes: array<ReactRouter.Routes.t>
let domRoutes: array<ReactRouter.Routes.t>
let beltRoutes: array<ReactRouter.Routes.t>
let default: Belt.Array.t<ReactRouter.Routes.t>
let blogArticleRoutes: array<ReactRouter.Routes.t>
let docsManualRoutes: array<ReactRouter.Routes.t>
let docsReactRoutes: array<ReactRouter.Routes.t>
let docsGuidelinesRoutes: array<ReactRouter.Routes.t>
let communityRoutes: array<ReactRouter.Routes.t>
let syntaxLookupDetailRoutes: array<ReactRouter.Routes.t>
let default: array<ReactRouter.Routes.t>
3 changes: 1 addition & 2 deletions app/routes/BlogRoute.res
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ type loaderData = {posts: array<BlogApi.post>, category: Blog.category}
let loader: ReactRouter.Loader.t<loaderData> = async ({request}) => {
let showArchived = request.url->String.includes("archived")
let posts = async () =>
(await Mdx.allMdx(~filterByPaths=["markdown-pages/blog"]))
->Mdx.filterMdxPages("blog")
(await MdxFile.loadAllAttributes(~dir="markdown-pages/blog"))
->Array.map(BlogLoader.transform)
->Array.toSorted((a, b) => {
a.frontmatter.date->DateStr.toDate > b.frontmatter.date->DateStr.toDate ? -1.0 : 1.0
Expand Down
32 changes: 5 additions & 27 deletions app/routes/CommunityRoute.res
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,16 @@ type loaderData = {
categories: array<SidebarLayout.Sidebar.Category.t>,
}

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))

let communityTableOfContents = async () => {
let groups =
(await Mdx.allMdx(~filterByPaths=["markdown-pages/community"]))
(await MdxFile.loadAllAttributes(~dir="markdown-pages/community"))
->Mdx.filterMdxPages("community")
->Mdx.groupBySection
->Dict.mapValues(values => values->Mdx.sortSection->convertToNavItems("/community"))
->Dict.mapValues(values =>
values->Mdx.sortSection->SidebarHelpers.convertToNavItems("/community")
)

getAllGroups(groups, ["Resources"])
SidebarHelpers.getAllGroups(groups, ["Resources"])
}

let loader: ReactRouter.Loader.t<loaderData> = async ({request}) => {
Expand Down
159 changes: 159 additions & 0 deletions app/routes/DocsManualRoute.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
type loaderData = {
compiledMdx: CompiledMdx.t,
categories: array<SidebarLayout.Sidebar.Category.t>,
entries: array<TableOfContents.entry>,
title: string,
description: string,
filePath: string,
}

// Build sidebar categories from all manual docs, sorted by their "order" field in frontmatter
let manualTableOfContents = async () => {
let groups =
(await MdxFile.loadAllAttributes(~dir="markdown-pages/docs"))
->Mdx.filterMdxPages("docs/manual")
->Mdx.groupBySection
->Dict.mapValues(values =>
values->Mdx.sortSection->SidebarHelpers.convertToNavItems("/docs/manual")
)

SidebarHelpers.getAllGroups(
groups,
[
"Overview",
"Guides",
"Language Features",
"JavaScript Interop",
"Build System",
"Advanced Features",
],
)
}

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/manual",
~alias="docs/manual",
)

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 manualTableOfContents()

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 Language Manual`,
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/manual/introduction"},
{
Url.name: "Language Manual",
href: "/docs/manual/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>
</>
}
8 changes: 3 additions & 5 deletions app/routes/MdxRoute.resi → app/routes/DocsManualRoute.resi
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
type loaderData = {
...Mdx.t,
compiledMdx: CompiledMdx.t,
categories: array<SidebarLayout.Sidebar.Category.t>,
entries: array<TableOfContents.entry>,
mdxSources?: array<SyntaxLookup.item>,
activeSyntaxItem?: SyntaxLookup.item,
breadcrumbs?: list<Url.breadcrumb>,
title: string,
filePath: option<string>,
description: string,
filePath: string,
}

let loader: ReactRouter.Loader.t<loaderData>
Expand Down
Loading
Loading