Skip to content

Hide top nav on reading docs on mobile #856

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 24, 2024
Merged
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
4 changes: 2 additions & 2 deletions src/Blog.res
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ let default = (props: props): React.element => {
</>
}

let overlayState = React.useState(() => false)
let (isOverlayOpen, setOverlayOpen) = React.useState(() => false)
let title = "Blog | ReScript Documentation"

<>
Expand All @@ -298,7 +298,7 @@ let default = (props: props): React.element => {
/>
<div className="mt-16 pt-2">
<div className="text-gray-80 text-18">
<Navigation overlayState />
<Navigation isOverlayOpen setOverlayOpen />
<div className="flex justify-center overflow-hidden">
<main className="min-w-320 lg:align-center w-full lg:px-0 max-w-1280 pb-48">
<MdxProvider components=MarkdownComponents.default>
Expand Down
8 changes: 4 additions & 4 deletions src/Packages.res
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,8 @@ type state =

let scrollToTop: unit => unit = %raw(`function() {
window.scroll({
top: 0,
left: 0,
top: 0,
left: 0,
behavior: 'smooth'
});
}
Expand Down Expand Up @@ -462,7 +462,7 @@ let default = (props: props) => {
None
}, [state])

let overlayState = React.useState(() => false)
let (isOverlayOpen, setOverlayOpen) = React.useState(() => false)
<>
<Meta
siteName="ReScript Packages"
Expand All @@ -471,7 +471,7 @@ let default = (props: props) => {
/>
<div className="mt-16 pt-2">
<div className="text-gray-80 text-18">
<Navigation overlayState />
<Navigation isOverlayOpen setOverlayOpen />
<div className="flex overflow-hidden">
<div
className="flex justify-between min-w-320 px-4 pt-16 lg:align-center w-full lg:px-8 pb-48">
Expand Down
4 changes: 2 additions & 2 deletions src/SyntaxLookup.res
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ let default = (props: props) => {
onSearchValueChange("")
}

let overlayState = React.useState(() => false)
let (isOverlayOpen, setOverlayOpen) = React.useState(() => false)
let title = "Syntax Lookup | ReScript Documentation"

let content =
Expand Down Expand Up @@ -372,7 +372,7 @@ let default = (props: props) => {
/>
<div className="mt-4 xs:mt-16">
<div className="text-gray-80">
<Navigation overlayState />
<Navigation isOverlayOpen setOverlayOpen />
<div className="flex xs:justify-center overflow-hidden pb-48">
<main className="mt-16 min-w-320 lg:align-center w-full px-4 md:px-8 max-w-1280">
<MdxProvider components=MarkdownComponents.default>
Expand Down
4 changes: 2 additions & 2 deletions src/Try.res
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
type props = {versions: array<string>}

let default = props => {
let overlayState = React.useState(() => false)
let (isOverlayOpen, setOverlayOpen) = React.useState(() => false)

let lazyPlayground = Next.Dynamic.dynamic(
async () => await Js.import(Playground.make),
Expand All @@ -20,7 +20,7 @@ let default = props => {
</Next.Head>
<div className="text-16">
<div className="text-gray-40 text-14">
<Navigation fixed=false overlayState />
<Navigation fixed=false isOverlayOpen setOverlayOpen />
playground
</div>
</div>
Expand Down
1 change: 0 additions & 1 deletion src/bindings/Next.res
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ module Link = {
~children: React.element,
~className: string=?,
~target: string=?,
~hrefRel: string=?,
) => React.element = "default"
}

Expand Down
1 change: 0 additions & 1 deletion src/bindings/Next.resi
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ module Link: {
~children: React.element,
~className: string=?,
~target: string=?,
~hrefRel: string=?,
) => React.element
}

Expand Down
1 change: 1 addition & 0 deletions src/bindings/Webapi.res
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ module Window = {
external removeEventListener: (string, 'a => unit) => unit = "removeEventListener"
@scope("window") @val external innerWidth: int = "innerWidth"
@scope("window") @val external innerHeight: int = "innerHeight"
@scope("window") @val external scrollY: int = "scrollY"
}

module Fetch = {
Expand Down
153 changes: 83 additions & 70 deletions src/common/App.res
Original file line number Diff line number Diff line change
Expand Up @@ -56,93 +56,106 @@ let make = (props: props): React.element => {
// docs routes
| {base: ["docs", "manual"], pagepath, version} =>
// check if it's an api route
switch Belt.Array.get(pagepath, 0) {
| Some("api") =>
switch version {
| Latest =>
switch (Belt.Array.length(pagepath), Belt.Array.get(pagepath, 1)) {
| (1, _) => <ApiOverviewLayout.Docs> content </ApiOverviewLayout.Docs>
<EnableCollapsibleNavbar>
{switch Belt.Array.get(pagepath, 0) {
| Some("api") =>
switch version {
| Latest =>
switch (Belt.Array.length(pagepath), Belt.Array.get(pagepath, 1)) {
| (1, _) => <ApiOverviewLayout.Docs> content </ApiOverviewLayout.Docs>
| _ => content
}
| Version("v8.0.0") =>
switch (Belt.Array.length(pagepath), Belt.Array.get(pagepath, 1)) {
| (1, _) => <ApiOverviewLayout8_0_0.Docs> content </ApiOverviewLayout8_0_0.Docs>
| (2, Some("js")) => <JsDocsLayout8_0_0.Prose> content </JsDocsLayout8_0_0.Prose>
| (2, Some("belt")) => <BeltDocsLayout8_0_0.Prose> content </BeltDocsLayout8_0_0.Prose>
| (_, Some("js")) => <JsDocsLayout8_0_0.Docs> content </JsDocsLayout8_0_0.Docs>
| (_, Some("belt")) => <BeltDocsLayout8_0_0.Docs> content </BeltDocsLayout8_0_0.Docs>
| (_, Some("dom")) => <DomDocsLayout8_0_0.Docs> content </DomDocsLayout8_0_0.Docs>
| _ => React.null
}
| Version("v9.0.0") =>
switch (Belt.Array.length(pagepath), Belt.Array.get(pagepath, 1)) {
| (1, _) => <ApiOverviewLayout9_0_0.Docs> content </ApiOverviewLayout9_0_0.Docs>
| (2, Some("js")) => <JsDocsLayout9_0_0.Prose> content </JsDocsLayout9_0_0.Prose>
| (2, Some("belt")) => <BeltDocsLayout9_0_0.Prose> content </BeltDocsLayout9_0_0.Prose>
| (_, Some("js")) => <JsDocsLayout9_0_0.Docs> content </JsDocsLayout9_0_0.Docs>
| (_, Some("belt")) => <BeltDocsLayout9_0_0.Docs> content </BeltDocsLayout9_0_0.Docs>
| (_, Some("dom")) => <DomDocsLayout9_0_0.Docs> content </DomDocsLayout9_0_0.Docs>
| _ => React.null
}
| Version("v10.0.0") =>
switch (Belt.Array.length(pagepath), Belt.Array.get(pagepath, 1)) {
| (1, _) => <ApiOverviewLayout10_0_0.Docs> content </ApiOverviewLayout10_0_0.Docs>
| (2, Some("js")) => <JsDocsLayout10_0_0.Prose> content </JsDocsLayout10_0_0.Prose>
| (2, Some("belt")) => <BeltDocsLayout10_0_0.Prose> content </BeltDocsLayout10_0_0.Prose>
| (_, Some("js")) => <JsDocsLayout10_0_0.Docs> content </JsDocsLayout10_0_0.Docs>
| (_, Some("belt")) => <BeltDocsLayout10_0_0.Docs> content </BeltDocsLayout10_0_0.Docs>
| (_, Some("dom")) => <DomDocsLayout10_0_0.Docs> content </DomDocsLayout10_0_0.Docs>
| _ => React.null
}
| _ => content
}
| Version("v8.0.0") =>
switch (Belt.Array.length(pagepath), Belt.Array.get(pagepath, 1)) {
| (1, _) => <ApiOverviewLayout8_0_0.Docs> content </ApiOverviewLayout8_0_0.Docs>
| (2, Some("js")) => <JsDocsLayout8_0_0.Prose> content </JsDocsLayout8_0_0.Prose>
| (2, Some("belt")) => <BeltDocsLayout8_0_0.Prose> content </BeltDocsLayout8_0_0.Prose>
| (_, Some("js")) => <JsDocsLayout8_0_0.Docs> content </JsDocsLayout8_0_0.Docs>
| (_, Some("belt")) => <BeltDocsLayout8_0_0.Docs> content </BeltDocsLayout8_0_0.Docs>
| (_, Some("dom")) => <DomDocsLayout8_0_0.Docs> content </DomDocsLayout8_0_0.Docs>
| _ => React.null
}
| Version("v9.0.0") =>
switch (Belt.Array.length(pagepath), Belt.Array.get(pagepath, 1)) {
| (1, _) => <ApiOverviewLayout9_0_0.Docs> content </ApiOverviewLayout9_0_0.Docs>
| (2, Some("js")) => <JsDocsLayout9_0_0.Prose> content </JsDocsLayout9_0_0.Prose>
| (2, Some("belt")) => <BeltDocsLayout9_0_0.Prose> content </BeltDocsLayout9_0_0.Prose>
| (_, Some("js")) => <JsDocsLayout9_0_0.Docs> content </JsDocsLayout9_0_0.Docs>
| (_, Some("belt")) => <BeltDocsLayout9_0_0.Docs> content </BeltDocsLayout9_0_0.Docs>
| (_, Some("dom")) => <DomDocsLayout9_0_0.Docs> content </DomDocsLayout9_0_0.Docs>
| _ =>
switch version {
| Latest =>
<ManualDocsLayout.Latest frontmatter={component->frontmatter}>
content
</ManualDocsLayout.Latest>
| Version("v8.0.0") =>
<ManualDocsLayout.V800 frontmatter={component->frontmatter}>
content
</ManualDocsLayout.V800>
| Version("v9.0.0") =>
<ManualDocsLayout.V900 frontmatter={component->frontmatter}>
content
</ManualDocsLayout.V900>
| Version("v10.0.0") =>
<ManualDocsLayout.V1000 frontmatter={component->frontmatter}>
content
</ManualDocsLayout.V1000>
| _ => React.null
}
| Version("v10.0.0") =>
switch (Belt.Array.length(pagepath), Belt.Array.get(pagepath, 1)) {
| (1, _) => <ApiOverviewLayout10_0_0.Docs> content </ApiOverviewLayout10_0_0.Docs>
| (2, Some("js")) => <JsDocsLayout10_0_0.Prose> content </JsDocsLayout10_0_0.Prose>
| (2, Some("belt")) => <BeltDocsLayout10_0_0.Prose> content </BeltDocsLayout10_0_0.Prose>
| (_, Some("js")) => <JsDocsLayout10_0_0.Docs> content </JsDocsLayout10_0_0.Docs>
| (_, Some("belt")) => <BeltDocsLayout10_0_0.Docs> content </BeltDocsLayout10_0_0.Docs>
| (_, Some("dom")) => <DomDocsLayout10_0_0.Docs> content </DomDocsLayout10_0_0.Docs>
| _ => React.null
}
| _ => content
}
| _ =>
switch version {
}}
</EnableCollapsibleNavbar>
| {base: ["docs", "react"], version} =>
<EnableCollapsibleNavbar>
{switch version {
| Latest =>
<ManualDocsLayout.Latest frontmatter={component->frontmatter}>
content
</ManualDocsLayout.Latest>
| Version("v8.0.0") =>
<ManualDocsLayout.V800 frontmatter={component->frontmatter}>
<ReactDocsLayout.Latest frontmatter={component->frontmatter}>
content
</ManualDocsLayout.V800>
| Version("v9.0.0") =>
<ManualDocsLayout.V900 frontmatter={component->frontmatter}>
</ReactDocsLayout.Latest>
| Version("v0.10.0") =>
<ReactDocsLayout.V0100 frontmatter={component->frontmatter}>
content
</ManualDocsLayout.V900>
| Version("v10.0.0") =>
<ManualDocsLayout.V1000 frontmatter={component->frontmatter}>
</ReactDocsLayout.V0100>
| Version("v0.11.0") =>
<ReactDocsLayout.V0110 frontmatter={component->frontmatter}>
content
</ManualDocsLayout.V1000>
</ReactDocsLayout.V0110>
| _ => React.null
}
}
| {base: ["docs", "react"], version} =>
switch version {
| Latest =>
<ReactDocsLayout.Latest frontmatter={component->frontmatter}>
content
</ReactDocsLayout.Latest>
| Version("v0.10.0") =>
<ReactDocsLayout.V0100 frontmatter={component->frontmatter}> content </ReactDocsLayout.V0100>
| Version("v0.11.0") =>
<ReactDocsLayout.V0110 frontmatter={component->frontmatter}> content </ReactDocsLayout.V0110>
| _ => React.null
}
}}
</EnableCollapsibleNavbar>
| {base: ["docs", "reason-compiler"], version: Latest} =>
<ReasonCompilerDocsLayout> content </ReasonCompilerDocsLayout>
<EnableCollapsibleNavbar>
<ReasonCompilerDocsLayout> content </ReasonCompilerDocsLayout>
</EnableCollapsibleNavbar>
// common routes
| {base} =>
switch Belt.List.fromArray(base) {
| list{"community", ..._rest} =>
<CommunityLayout frontmatter={component->frontmatter}> content </CommunityLayout>
<EnableCollapsibleNavbar>
<CommunityLayout frontmatter={component->frontmatter}> content </CommunityLayout>
</EnableCollapsibleNavbar>
| list{"try"} => content
| list{"blog"} => content // Blog implements its own layout as well
| list{"syntax-lookup"} => content
| list{"packages"} => content
| list{"blog", ..._rest} => // Here, the layout will be handled by the Blog_Article component
| list{"syntax-lookup"} => <EnableCollapsibleNavbar> content </EnableCollapsibleNavbar>
| list{"packages"} => <EnableCollapsibleNavbar> content </EnableCollapsibleNavbar>
| list{"blog", ..._rest} =>
// Here, the layout will be handled by the Blog_Article component
// to keep the frontmatter parsing etc in one place
content
<EnableCollapsibleNavbar> content </EnableCollapsibleNavbar>
| _ =>
let fm = component->frontmatter->DocFrontmatter.decode
let title = switch url {
Expand Down
12 changes: 12 additions & 0 deletions src/common/EnableCollapsibleNavbar.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@react.component
let make = (~children) => {
let scrollDir = Hooks.useScrollDirection()

<div
className={switch scrollDir {
| Up(_) => "group nav-appear"
| Down(_) => "group nav-disappear"
}}>
children
</div>
}
57 changes: 30 additions & 27 deletions src/common/Hooks.res
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
/* Contains some generic hooks */
%%raw("import React from 'react'")

let useOutsideClick: (ReactDOM.Ref.t, unit => unit) => unit = %raw(`(outerRef, trigger) => {
function handleClickOutside(event) {
if (outerRef.current && !outerRef.current.contains(event.target)) {
Expand All @@ -16,33 +14,38 @@ let useOutsideClick: (ReactDOM.Ref.t, unit => unit) => unit = %raw(`(outerRef, t
});
}`)

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

function getSize() {
return {
width: isClient ? window.innerWidth : undefined,
height: isClient ? window.innerHeight : undefined
};
}

const [windowSize, setWindowSize] = React.useState(getSize);
/**
This will cause highly frequent events, so use it only once in a root as possible.
And split the children components to prevent heavy ones from being re-rendered unnecessarily. */
let useScrollDirection = () => {
let (_, startScrollEventTransition) = React.useTransition()
let (scrollDir, setScrollDir) = React.useState(() => Up({scrollY: %raw(`Infinity`)}))

React.useEffect(() => {
if (!isClient) {
return false;
let onScroll = _e => {
startScrollEventTransition(() => {
setScrollDir(
prev => {
let Up({scrollY}) | Down({scrollY}) = prev
if scrollY === 0 || scrollY > Webapi.Window.scrollY {
Up({scrollY: Webapi.Window.scrollY})
} else {
Down({scrollY: Webapi.Window.scrollY})
}
},
)
})
}
Webapi.Window.addEventListener("scroll", onScroll)
Some(() => Webapi.Window.removeEventListener("scroll", onScroll))
}, [])

function handleResize() {
setWindowSize(getSize());
}

window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []); // Empty array ensures that effect is only run on mount and unmount

if(windowSize) {
return windowSize.width;
}
return null;
}`)
scrollDir
}
2 changes: 2 additions & 0 deletions src/components/Footer.res
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,5 @@ let make = () => {
</div>
</footer>
}

let make = React.memo(make)
6 changes: 1 addition & 5 deletions src/components/Markdown.res
Original file line number Diff line number Diff line change
Expand Up @@ -380,11 +380,7 @@ module A = {
| [pathname] => Js.String2.replaceByRe(pathname, regex, "")
| _ => href
}
<Next.Link
href
hrefRel="noopener noreferrer"
className="no-underline text-fire hover:underline"
?target>
<Next.Link href className="no-underline text-fire hover:underline" ?target>
children
</Next.Link>
}
Expand Down
Loading