Skip to content

Commit 62b15f4

Browse files
committed
fix anchor links
1 parent 9f8c670 commit 62b15f4

File tree

9 files changed

+56
-57
lines changed

9 files changed

+56
-57
lines changed

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"isbot": "^5",
4444
"lz-string": "^1.5.0",
4545
"mdast-util-from-markdown": "^2.0.2",
46+
"mdast-util-to-string": "^4.0.0",
4647
"mdast-util-toc": "^7.1.0",
4748
"patch-package": "^8.0.1",
4849
"react": "^19.1.0",

src/Mdx.res

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ external gfm: remarkPlugin = "default"
7070
@module("remark-validate-links")
7171
external validateLinks: remarkPlugin = "default"
7272

73+
@module("mdast-util-to-string")
74+
external childrenToString: {..} => string = "toString"
75+
7376
// The loadAllMdx function logs out all of the file contents as it reads them, which is noisy and not useful.
7477
// We can suppress that logging with this helper function.
7578
let allMdx = async (~filterByPaths: option<array<string>>=?) =>
@@ -199,4 +202,23 @@ let remarkReScriptPreludePlugin = makePlugin(_options =>
199202

200203
let remarkLinkPlugin = makePlugin(_options => (tree, vfile) => remarkLinkPlugin(tree, vfile))
201204

202-
let plugins = [remarkLinkPlugin, gfm, remarkReScriptPreludePlugin]
205+
// converts the inner text of headings to kebab-case IDs
206+
let anchorLinkPlugin = (tree, _vfile) => {
207+
visit(tree, "heading", node => {
208+
let planText = childrenToString(node)
209+
let nodeData = switch node["data"] {
210+
| Some(data) => data
211+
| None => {
212+
"hProperties": {
213+
"id": planText->Url.normalizeAnchor,
214+
"title": planText,
215+
},
216+
}
217+
}
218+
node["data"] = nodeData
219+
})
220+
}
221+
222+
let anchorLinkPlugin = makePlugin(_options => (tree, vfile) => anchorLinkPlugin(tree, vfile))
223+
224+
let plugins = [remarkLinkPlugin, gfm, remarkReScriptPreludePlugin, anchorLinkPlugin]

src/common/Util.res

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ module String = {
77
return str.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); });
88
}")
99

10+
let kebabCase = string =>
11+
string
12+
->String.replaceAllRegExp(/([a-z])([A-Z])/g, "$1-$2")
13+
->String.toLowerCase
14+
->String.replaceAll(" ", "-")
15+
1016
let capitalize: string => string = %raw("str => {
1117
return str && str.charAt(0).toUpperCase() + str.substring(1);
1218
}")

src/common/Util.resi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module Unsafe: {
1010

1111
module String: {
1212
let camelCase: string => string
13+
let kebabCase: string => string
1314
let capitalize: string => string
1415
let capitalizeSentence: string => string
1516
let leadingSlash: string => string

src/components/ApiMarkdown.res

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ module H2 = {
1010
// We will currently hide the headline, to keep the structure,
1111
// but having an Elm like documentation
1212
@react.component
13-
let make = (~id, ~children) => <>
13+
let make = (~id, ~children, ~title) => <>
1414
<div className="mb-10 mt-20" />
15-
<Markdown.H2 id> children </Markdown.H2>
15+
<Markdown.H2 id title> children </Markdown.H2>
1616
</>
1717
}
1818

19-
type aliasH2 = Markdown.H2.props<string, React.element> => React.element
19+
type aliasH2 = Markdown.H2.props<string, React.element, string> => React.element
2020
external asMarkdownH2: 'a => aliasH2 = "%identity"
2121

2222
let default = {

src/components/Markdown.res

Lines changed: 12 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// This file was automatically converted to ReScript from 'Markdown.re'
22
// Check the output and make sure to delete the original file
3-
external childrenToString: React.element => string = "%identity"
43

54
module P = {
65
@react.component
@@ -110,15 +109,11 @@ module UrlBox = {
110109

111110
// Used for creating invisible, hoverable <a> anchors for url linking
112111
module Anchor = {
113-
// Todo: Headers with nested components don't pass a string, we need to flatten
114-
// everything to a single string first before we are able to use this id transformation
115-
// function
116-
117112
@react.component
118-
let make = (~id: string, ~title: string) => {
119-
<span className="inline group relative" title>
113+
let make = (~id: string, ~title: option<string>=?) => {
114+
<span className="inline group relative" title=?title>
120115
<a
121-
title
116+
title=?title
122117
className="scroll-mt-30 invisible text-gray-60 opacity-50 hover:opacity-100 hover:text-gray-60 hover:cursor-pointer group-hover:visible"
123118
href={"#" ++ id}
124119
id={id}
@@ -137,20 +132,14 @@ module H1 = {
137132

138133
module H2 = {
139134
@react.component
140-
let make = (~id, ~children) => {
135+
let make = (~id, ~children, ~title=?) => {
141136
// Children may not be a string
142-
let title = {
143-
try {
144-
childrenToString(children)->Url.normalizeAnchor
145-
} catch {
146-
| _ => ""
147-
}
148-
}
137+
149138
<>
150139
<h2 id className="group mt-16 mb-3 hl-3 scroll-mt-32">
151140
children
152141
<span className="ml-2">
153-
<Anchor title={title} id={title} />
142+
<Anchor ?title id />
154143
</span>
155144
</h2>
156145
</>
@@ -159,59 +148,38 @@ module H2 = {
159148

160149
module H3 = {
161150
@react.component
162-
let make = (~id, ~children) => {
163-
let title = {
164-
try {
165-
childrenToString(children)->Url.normalizeAnchor
166-
} catch {
167-
| _ => ""
168-
}
169-
}
151+
let make = (~id, ~children, ~title=?) => {
170152
<h3 id className="group mt-8 mb-4 hl-4 scroll-mt-32">
171153
children
172154
<span className="ml-2">
173-
<Anchor title={title} id={title->encodeURIComponent} />
155+
<Anchor ?title id={id} />
174156
</span>
175157
</h3>
176158
}
177159
}
178160

179161
module H4 = {
180162
@react.component
181-
let make = (~id, ~children) => {
182-
let title = {
183-
try {
184-
childrenToString(children)->Url.normalizeAnchor
185-
} catch {
186-
| _ => ""
187-
}
188-
}
163+
let make = (~id, ~children, ~title=?) => {
189164
<h4 id className="group mt-8 hl-5 scroll-mt-32">
190165
children
191166
<span className="ml-2">
192-
<Anchor title={title} id={title->encodeURIComponent} />
167+
<Anchor ?title id />
193168
</span>
194169
</h4>
195170
}
196171
}
197172

198173
module H5 = {
199174
@react.component
200-
let make = (~id, ~children) => {
201-
let title = {
202-
try {
203-
childrenToString(children)->Url.normalizeAnchor
204-
} catch {
205-
| _ => ""
206-
}
207-
}
175+
let make = (~id, ~children, ~title=?) => {
208176
<h5
209177
id
210178
className="group mt-12 mb-3 text-12 leading-2 font-sans font-semibold uppercase tracking-wide text-gray-80"
211179
>
212180
children
213181
<span className="ml-2">
214-
<Anchor title={title} id={title->encodeURIComponent} />
182+
<Anchor ?title id />
215183
</span>
216184
</h5>
217185
}

src/components/Markdown.resi

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ module Anchor: {
3535
/* let idFormat = (id: string): string => id */
3636

3737
@react.component
38-
let make: (~id: string, ~title: string) => React.element
38+
let make: (~id: string, ~title: string=?) => React.element
3939
}
4040

4141
module H1: {
@@ -45,22 +45,22 @@ module H1: {
4545

4646
module H2: {
4747
@react.component
48-
let make: (~id: string, ~children: React.element) => React.element
48+
let make: (~id: string, ~children: React.element, ~title: string=?) => React.element
4949
}
5050

5151
module H3: {
5252
@react.component
53-
let make: (~id: string, ~children: React.element) => React.element
53+
let make: (~id: string, ~children: React.element, ~title: string=?) => React.element
5454
}
5555

5656
module H4: {
5757
@react.component
58-
let make: (~id: string, ~children: React.element) => React.element
58+
let make: (~id: string, ~children: React.element, ~title: string=?) => React.element
5959
}
6060

6161
module H5: {
6262
@react.component
63-
let make: (~id: string, ~children: React.element) => React.element
63+
let make: (~id: string, ~children: React.element, ~title: string=?) => React.element
6464
}
6565

6666
module Pre: {

src/components/MarkdownComponents.res

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ type t = {
2828
p?: P.props<React.element> => React.element,
2929
li?: Li.props<React.element> => React.element,
3030
h1?: H1.props<React.element> => React.element,
31-
h2?: H2.props<string, React.element> => React.element,
32-
h3?: H3.props<string, React.element> => React.element,
33-
h4?: H4.props<string, React.element> => React.element,
34-
h5?: H5.props<string, React.element> => React.element,
31+
h2?: H2.props<string, React.element, string> => React.element,
32+
h3?: H3.props<string, React.element, string> => React.element,
33+
h4?: H4.props<string, React.element, string> => React.element,
34+
h5?: H5.props<string, React.element, string> => React.element,
3535
ul?: Ul.props<React.element> => React.element,
3636
ol?: Ol.props<React.element> => React.element,
3737
table?: Table.props<React.element> => React.element,

0 commit comments

Comments
 (0)