Skip to content

Commit 4e6f60c

Browse files
committed
feature as composition
1 parent 53d3fb8 commit 4e6f60c

12 files changed

+130
-160
lines changed

src/ApiDocs.res

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,6 @@ let default = (props: props) => {
374374
metaTitle={title ++ " | ReScript API"}
375375
theme=#Reason
376376
components=ApiMarkdown.default
377-
navbarCollapsible=true
378377
sidebarState=(isSidebarOpen, setSidebarOpen)
379378
sidebar
380379
rightSidebar>

src/BlogArticle.res

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ let default = (props: props) => {
199199
</Markdown.Warn>
200200
</div>
201201
}
202-
<MainLayout navbarCollapsible=true> content </MainLayout>
202+
<MainLayout> content </MainLayout>
203203
}
204204

205205
let getStaticProps: Next.GetStaticProps.t<props, Params.t> = async ctx => {

src/common/App.res

Lines changed: 83 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -56,93 +56,106 @@ let make = (props: props): React.element => {
5656
// docs routes
5757
| {base: ["docs", "manual"], pagepath, version} =>
5858
// check if it's an api route
59-
switch Belt.Array.get(pagepath, 0) {
60-
| Some("api") =>
61-
switch version {
62-
| Latest =>
63-
switch (Belt.Array.length(pagepath), Belt.Array.get(pagepath, 1)) {
64-
| (1, _) => <ApiOverviewLayout.Docs> content </ApiOverviewLayout.Docs>
59+
<EnableCollapsibleNavbar>
60+
{switch Belt.Array.get(pagepath, 0) {
61+
| Some("api") =>
62+
switch version {
63+
| Latest =>
64+
switch (Belt.Array.length(pagepath), Belt.Array.get(pagepath, 1)) {
65+
| (1, _) => <ApiOverviewLayout.Docs> content </ApiOverviewLayout.Docs>
66+
| _ => content
67+
}
68+
| Version("v8.0.0") =>
69+
switch (Belt.Array.length(pagepath), Belt.Array.get(pagepath, 1)) {
70+
| (1, _) => <ApiOverviewLayout8_0_0.Docs> content </ApiOverviewLayout8_0_0.Docs>
71+
| (2, Some("js")) => <JsDocsLayout8_0_0.Prose> content </JsDocsLayout8_0_0.Prose>
72+
| (2, Some("belt")) => <BeltDocsLayout8_0_0.Prose> content </BeltDocsLayout8_0_0.Prose>
73+
| (_, Some("js")) => <JsDocsLayout8_0_0.Docs> content </JsDocsLayout8_0_0.Docs>
74+
| (_, Some("belt")) => <BeltDocsLayout8_0_0.Docs> content </BeltDocsLayout8_0_0.Docs>
75+
| (_, Some("dom")) => <DomDocsLayout8_0_0.Docs> content </DomDocsLayout8_0_0.Docs>
76+
| _ => React.null
77+
}
78+
| Version("v9.0.0") =>
79+
switch (Belt.Array.length(pagepath), Belt.Array.get(pagepath, 1)) {
80+
| (1, _) => <ApiOverviewLayout9_0_0.Docs> content </ApiOverviewLayout9_0_0.Docs>
81+
| (2, Some("js")) => <JsDocsLayout9_0_0.Prose> content </JsDocsLayout9_0_0.Prose>
82+
| (2, Some("belt")) => <BeltDocsLayout9_0_0.Prose> content </BeltDocsLayout9_0_0.Prose>
83+
| (_, Some("js")) => <JsDocsLayout9_0_0.Docs> content </JsDocsLayout9_0_0.Docs>
84+
| (_, Some("belt")) => <BeltDocsLayout9_0_0.Docs> content </BeltDocsLayout9_0_0.Docs>
85+
| (_, Some("dom")) => <DomDocsLayout9_0_0.Docs> content </DomDocsLayout9_0_0.Docs>
86+
| _ => React.null
87+
}
88+
| Version("v10.0.0") =>
89+
switch (Belt.Array.length(pagepath), Belt.Array.get(pagepath, 1)) {
90+
| (1, _) => <ApiOverviewLayout10_0_0.Docs> content </ApiOverviewLayout10_0_0.Docs>
91+
| (2, Some("js")) => <JsDocsLayout10_0_0.Prose> content </JsDocsLayout10_0_0.Prose>
92+
| (2, Some("belt")) => <BeltDocsLayout10_0_0.Prose> content </BeltDocsLayout10_0_0.Prose>
93+
| (_, Some("js")) => <JsDocsLayout10_0_0.Docs> content </JsDocsLayout10_0_0.Docs>
94+
| (_, Some("belt")) => <BeltDocsLayout10_0_0.Docs> content </BeltDocsLayout10_0_0.Docs>
95+
| (_, Some("dom")) => <DomDocsLayout10_0_0.Docs> content </DomDocsLayout10_0_0.Docs>
96+
| _ => React.null
97+
}
6598
| _ => content
6699
}
67-
| Version("v8.0.0") =>
68-
switch (Belt.Array.length(pagepath), Belt.Array.get(pagepath, 1)) {
69-
| (1, _) => <ApiOverviewLayout8_0_0.Docs> content </ApiOverviewLayout8_0_0.Docs>
70-
| (2, Some("js")) => <JsDocsLayout8_0_0.Prose> content </JsDocsLayout8_0_0.Prose>
71-
| (2, Some("belt")) => <BeltDocsLayout8_0_0.Prose> content </BeltDocsLayout8_0_0.Prose>
72-
| (_, Some("js")) => <JsDocsLayout8_0_0.Docs> content </JsDocsLayout8_0_0.Docs>
73-
| (_, Some("belt")) => <BeltDocsLayout8_0_0.Docs> content </BeltDocsLayout8_0_0.Docs>
74-
| (_, Some("dom")) => <DomDocsLayout8_0_0.Docs> content </DomDocsLayout8_0_0.Docs>
75-
| _ => React.null
76-
}
77-
| Version("v9.0.0") =>
78-
switch (Belt.Array.length(pagepath), Belt.Array.get(pagepath, 1)) {
79-
| (1, _) => <ApiOverviewLayout9_0_0.Docs> content </ApiOverviewLayout9_0_0.Docs>
80-
| (2, Some("js")) => <JsDocsLayout9_0_0.Prose> content </JsDocsLayout9_0_0.Prose>
81-
| (2, Some("belt")) => <BeltDocsLayout9_0_0.Prose> content </BeltDocsLayout9_0_0.Prose>
82-
| (_, Some("js")) => <JsDocsLayout9_0_0.Docs> content </JsDocsLayout9_0_0.Docs>
83-
| (_, Some("belt")) => <BeltDocsLayout9_0_0.Docs> content </BeltDocsLayout9_0_0.Docs>
84-
| (_, Some("dom")) => <DomDocsLayout9_0_0.Docs> content </DomDocsLayout9_0_0.Docs>
100+
| _ =>
101+
switch version {
102+
| Latest =>
103+
<ManualDocsLayout.Latest frontmatter={component->frontmatter}>
104+
content
105+
</ManualDocsLayout.Latest>
106+
| Version("v8.0.0") =>
107+
<ManualDocsLayout.V800 frontmatter={component->frontmatter}>
108+
content
109+
</ManualDocsLayout.V800>
110+
| Version("v9.0.0") =>
111+
<ManualDocsLayout.V900 frontmatter={component->frontmatter}>
112+
content
113+
</ManualDocsLayout.V900>
114+
| Version("v10.0.0") =>
115+
<ManualDocsLayout.V1000 frontmatter={component->frontmatter}>
116+
content
117+
</ManualDocsLayout.V1000>
85118
| _ => React.null
86119
}
87-
| Version("v10.0.0") =>
88-
switch (Belt.Array.length(pagepath), Belt.Array.get(pagepath, 1)) {
89-
| (1, _) => <ApiOverviewLayout10_0_0.Docs> content </ApiOverviewLayout10_0_0.Docs>
90-
| (2, Some("js")) => <JsDocsLayout10_0_0.Prose> content </JsDocsLayout10_0_0.Prose>
91-
| (2, Some("belt")) => <BeltDocsLayout10_0_0.Prose> content </BeltDocsLayout10_0_0.Prose>
92-
| (_, Some("js")) => <JsDocsLayout10_0_0.Docs> content </JsDocsLayout10_0_0.Docs>
93-
| (_, Some("belt")) => <BeltDocsLayout10_0_0.Docs> content </BeltDocsLayout10_0_0.Docs>
94-
| (_, Some("dom")) => <DomDocsLayout10_0_0.Docs> content </DomDocsLayout10_0_0.Docs>
95-
| _ => React.null
96-
}
97-
| _ => content
98-
}
99-
| _ =>
100-
switch version {
120+
}}
121+
</EnableCollapsibleNavbar>
122+
| {base: ["docs", "react"], version} =>
123+
<EnableCollapsibleNavbar>
124+
{switch version {
101125
| Latest =>
102-
<ManualDocsLayout.Latest frontmatter={component->frontmatter}>
103-
content
104-
</ManualDocsLayout.Latest>
105-
| Version("v8.0.0") =>
106-
<ManualDocsLayout.V800 frontmatter={component->frontmatter}>
126+
<ReactDocsLayout.Latest frontmatter={component->frontmatter}>
107127
content
108-
</ManualDocsLayout.V800>
109-
| Version("v9.0.0") =>
110-
<ManualDocsLayout.V900 frontmatter={component->frontmatter}>
128+
</ReactDocsLayout.Latest>
129+
| Version("v0.10.0") =>
130+
<ReactDocsLayout.V0100 frontmatter={component->frontmatter}>
111131
content
112-
</ManualDocsLayout.V900>
113-
| Version("v10.0.0") =>
114-
<ManualDocsLayout.V1000 frontmatter={component->frontmatter}>
132+
</ReactDocsLayout.V0100>
133+
| Version("v0.11.0") =>
134+
<ReactDocsLayout.V0110 frontmatter={component->frontmatter}>
115135
content
116-
</ManualDocsLayout.V1000>
136+
</ReactDocsLayout.V0110>
117137
| _ => React.null
118-
}
119-
}
120-
| {base: ["docs", "react"], version} =>
121-
switch version {
122-
| Latest =>
123-
<ReactDocsLayout.Latest frontmatter={component->frontmatter}>
124-
content
125-
</ReactDocsLayout.Latest>
126-
| Version("v0.10.0") =>
127-
<ReactDocsLayout.V0100 frontmatter={component->frontmatter}> content </ReactDocsLayout.V0100>
128-
| Version("v0.11.0") =>
129-
<ReactDocsLayout.V0110 frontmatter={component->frontmatter}> content </ReactDocsLayout.V0110>
130-
| _ => React.null
131-
}
138+
}}
139+
</EnableCollapsibleNavbar>
132140
| {base: ["docs", "reason-compiler"], version: Latest} =>
133-
<ReasonCompilerDocsLayout> content </ReasonCompilerDocsLayout>
141+
<EnableCollapsibleNavbar>
142+
<ReasonCompilerDocsLayout> content </ReasonCompilerDocsLayout>
143+
</EnableCollapsibleNavbar>
134144
// common routes
135145
| {base} =>
136146
switch Belt.List.fromArray(base) {
137147
| list{"community", ..._rest} =>
138-
<CommunityLayout frontmatter={component->frontmatter}> content </CommunityLayout>
148+
<EnableCollapsibleNavbar>
149+
<CommunityLayout frontmatter={component->frontmatter}> content </CommunityLayout>
150+
</EnableCollapsibleNavbar>
139151
| list{"try"} => content
140152
| list{"blog"} => content // Blog implements its own layout as well
141-
| list{"syntax-lookup"} => content
142-
| list{"packages"} => content
143-
| list{"blog", ..._rest} => // Here, the layout will be handled by the Blog_Article component
153+
| list{"syntax-lookup"} => <EnableCollapsibleNavbar> content </EnableCollapsibleNavbar>
154+
| list{"packages"} => <EnableCollapsibleNavbar> content </EnableCollapsibleNavbar>
155+
| list{"blog", ..._rest} =>
156+
// Here, the layout will be handled by the Blog_Article component
144157
// to keep the frontmatter parsing etc in one place
145-
content
158+
<EnableCollapsibleNavbar> content </EnableCollapsibleNavbar>
146159
| _ =>
147160
let fm = component->frontmatter->DocFrontmatter.decode
148161
let title = switch url {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@react.component
2+
let make = (~children) => {
3+
let scrollDir = Hooks.useScrollDirection()
4+
5+
<div
6+
className={switch scrollDir {
7+
| Up(_) => "group nav-appear"
8+
| Down(_) => "group nav-disappear"
9+
}}>
10+
children
11+
</div>
12+
}

src/common/Hooks.res

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
/* Contains some generic hooks */
2-
%%raw("import React from 'react'")
3-
42
let useOutsideClick: (ReactDOM.Ref.t, unit => unit) => unit = %raw(`(outerRef, trigger) => {
53
function handleClickOutside(event) {
64
if (outerRef.current && !outerRef.current.contains(event.target)) {
@@ -16,33 +14,38 @@ let useOutsideClick: (ReactDOM.Ref.t, unit => unit) => unit = %raw(`(outerRef, t
1614
});
1715
}`)
1816

19-
let useWindowWidth: unit => option<int> = %raw(` () => {
20-
const isClient = typeof window === 'object';
17+
/** scrollDir is not memo-friendly.
18+
It must be used with pattern matching.
19+
Do not pass it directly to child components. */
20+
type scrollDir =
21+
| Up({scrollY: int})
22+
| Down({scrollY: int})
2123

22-
function getSize() {
23-
return {
24-
width: isClient ? window.innerWidth : undefined,
25-
height: isClient ? window.innerHeight : undefined
26-
};
27-
}
28-
29-
const [windowSize, setWindowSize] = React.useState(getSize);
24+
/**
25+
This will cause highly frequent events, so use it only once in a root as possible.
26+
And split the children components to prevent heavy ones from being re-rendered unnecessarily. */
27+
let useScrollDirection = () => {
28+
let (_, startScrollEventTransition) = React.useTransition()
29+
let (scrollDir, setScrollDir) = React.useState(() => Up({scrollY: %raw(`Infinity`)}))
3030

3131
React.useEffect(() => {
32-
if (!isClient) {
33-
return false;
32+
let onScroll = _e => {
33+
startScrollEventTransition(() => {
34+
setScrollDir(
35+
prev => {
36+
let Up({scrollY}) | Down({scrollY}) = prev
37+
if scrollY === 0 || scrollY > Webapi.Window.scrollY {
38+
Up({scrollY: Webapi.Window.scrollY})
39+
} else {
40+
Down({scrollY: Webapi.Window.scrollY})
41+
}
42+
},
43+
)
44+
})
3445
}
46+
Webapi.Window.addEventListener("scroll", onScroll)
47+
Some(() => Webapi.Window.removeEventListener("scroll", onScroll))
48+
}, [])
3549

36-
function handleResize() {
37-
setWindowSize(getSize());
38-
}
39-
40-
window.addEventListener('resize', handleResize);
41-
return () => window.removeEventListener('resize', handleResize);
42-
}, []); // Empty array ensures that effect is only run on mount and unmount
43-
44-
if(windowSize) {
45-
return windowSize.width;
46-
}
47-
return null;
48-
}`)
50+
scrollDir
51+
}

src/common/ScrollDirectionHook.res

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/layouts/ApiLayout.res

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ let make = (
133133
metaTitle={pageTitle ++ " | ReScript API"}
134134
theme=#Reason
135135
components
136-
navbarCollapsible=true
137136
sidebarState=(isSidebarOpen, setSidebarOpen)
138137
sidebar>
139138
children

src/layouts/DocsLayout.res

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,6 @@ let make = (
152152
metaTitle
153153
theme
154154
components
155-
navbarCollapsible=true
156155
sidebarState=(isSidebarOpen, setSidebarOpen)
157156
sidebar
158157
categories

src/layouts/MainLayout.res

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,9 @@
11
@react.component
2-
let make = (~components=MarkdownComponents.default, ~navbarCollapsible=false, ~children) => {
2+
let make = (~components=MarkdownComponents.default, ~children) => {
33
let (isOverlayOpen, setOverlayOpen) = React.useState(() => false)
4-
let scrollDir = ScrollDirectionHook.useScrollDirection()
5-
6-
let navAppearanceCascading = switch (navbarCollapsible, scrollDir) {
7-
| (true, Up(_)) => " group nav-appear"
8-
| (true, Down(_)) => " group nav-disappear"
9-
| _ => ""
10-
}
114

125
<>
13-
<div className={"mt-4 xs:mt-16" ++ navAppearanceCascading}>
6+
<div className={"mt-4 xs:mt-16"}>
147
<div className="text-gray-80">
158
<Navigation isOverlayOpen setOverlayOpen />
169
<div className="flex xs:justify-center overflow-hidden pb-48">

src/layouts/MainLayout.resi

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,2 @@
11
@react.component
2-
let make: (
3-
~components: MarkdownComponents.t=?,
4-
~navbarCollapsible: bool=?,
5-
~children: React.element,
6-
) => React.element
2+
let make: (~components: MarkdownComponents.t=?, ~children: React.element) => React.element

src/layouts/SidebarLayout.res

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -218,11 +218,9 @@ let make = (
218218
~rightSidebar: option<React.element>=?,
219219
~categories: option<array<Sidebar.Category.t>>=?,
220220
~breadcrumbs: option<list<Url.breadcrumb>>=?,
221-
~navbarCollapsible=false,
222221
~children,
223222
) => {
224223
let (isNavOpen, setNavOpen) = React.useState(() => false)
225-
let scrollDir = ScrollDirectionHook.useScrollDirection()
226224
let router = Next.Router.useRouter()
227225
let version = Url.parse(router.route).version
228226

@@ -304,15 +302,9 @@ let make = (
304302
| None => React.null
305303
}
306304

307-
let navAppearanceCascading = switch (navbarCollapsible, scrollDir) {
308-
| (true, Up(_)) => " group nav-appear"
309-
| (true, Down(_)) => " group nav-disappear"
310-
| _ => ""
311-
}
312-
313305
<>
314306
<Meta title=metaTitle version />
315-
<div className={"mt-16 min-w-320 " ++ theme ++ navAppearanceCascading}>
307+
<div className={"mt-16 min-w-320 " ++ theme}>
316308
<div className="w-full">
317309
<Navigation isOverlayOpen=isNavOpen setOverlayOpen=setNavOpen />
318310
<div className="flex lg:justify-center">

src/layouts/SidebarLayout.resi

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,5 @@ let make: (
7373
~rightSidebar: React.element=?,
7474
~categories: array<Sidebar.Category.t>=?,
7575
~breadcrumbs: list<Url.breadcrumb>=?,
76-
~navbarCollapsible: bool=?,
7776
~children: React.element,
7877
) => React.element

0 commit comments

Comments
 (0)