Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.
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
90 changes: 79 additions & 11 deletions src/components/Article/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ interface Props {
previous?: PaginationInfo;
}

const NAV_HEIGHT = 72;

const Article = ({
title,
html,
Expand All @@ -23,16 +25,82 @@ const Article = ({
next,
relativePath,
authors,
}: Props): JSX.Element => (
<article className="article-reader">
<h1 className="article-reader__headline">{title}</h1>
<TOC heading="TABLE OF CONTENTS" tableOfContents={tableOfContents} />
{/* eslint-disable-next-line react/no-danger */}
<div dangerouslySetInnerHTML={{ __html: html }} />
<AuthorsList authors={authors} />
<EditLink relativePath={relativePath} />
<Pagination previous={previous} next={next} />
</article>
);
}: Props): JSX.Element => {
const element = React.useRef<HTMLElement | null>(null);

const handleRef = (ref?: HTMLElement | null): void => {
if (ref) {
element.current = ref;
}
};

React.useEffect((): (() => void) => {
let observer: IntersectionObserver;

if (window.history.state && window.history.state.articleScrollTo) {
window.scrollTo({
top: window.history.state.articleScrollTo,
});
}

if (element.current) {
observer = new IntersectionObserver(
(entries): void => {
entries.forEach((entry): void => {
// element is already hidden by the nav
if (entry.boundingClientRect.y < NAV_HEIGHT) {
if (!entry.target.previousElementSibling) {
window.history.replaceState(
{
articleScrollTo: null,
},
'',
null
);
return;
}

window.history.replaceState(
{
articleScrollTo: document.documentElement.scrollTop,
},
'',
null
);
}
});
},
{
threshold: [0.25, 0.5, 0.75],
rootMargin: `-${NAV_HEIGHT}px 0px 0px 0px`,
}
);

Array.from(element.current.children).forEach((children): void => {
observer.observe(children);
});
}

return (): void => {
if (observer && element.current) {
Array.from(element.current.children).forEach((children): void => {
observer.unobserve(children);
});
}
};
}, []);

return (
<article className="article-reader">
<h1 className="article-reader__headline">{title}</h1>
<TOC heading="TABLE OF CONTENTS" tableOfContents={tableOfContents} />
{/* eslint-disable-next-line react/no-danger */}
<div ref={handleRef} dangerouslySetInnerHTML={{ __html: html }} />
<AuthorsList authors={authors} />
<EditLink relativePath={relativePath} />
<Pagination previous={previous} next={next} />
</article>
);
};

export default Article;
12 changes: 5 additions & 7 deletions src/components/NavigationItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,12 @@ const NavigationItem = ({
}
};

useEffect(
(): void => {
if (element.current) {
const height = element.current.getBoundingClientRect().top;
autoScroll(height);
}
useEffect((): void => {
if (element.current) {
const height = element.current.getBoundingClientRect().top;
autoScroll(height);
}
);
});

return (
<Link
Expand Down
22 changes: 10 additions & 12 deletions src/components/Pagination/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,18 @@ const ulStyles: SerializedStyles = css`
const Pagination = ({ previous, next }: Props): JSX.Element => (
<ul css={ulStyles}>
<li>
{previous &&
previous.title && (
<Link css={link} to={`/learn/${previous.slug}`} rel="prev">
← &nbsp; Prev
</Link>
)}
{previous && previous.title && (
<Link css={link} to={`/learn/${previous.slug}`} rel="prev">
← &nbsp; Prev
</Link>
)}
</li>
<li>
{next &&
next.title && (
<Link css={link} to={`/learn/${next.slug}`} rel="next">
Next &nbsp; →
</Link>
)}
{next && next.title && (
<Link css={link} to={`/learn/${next.slug}`} rel="next">
Next &nbsp; →
</Link>
)}
</li>
</ul>
);
Expand Down
50 changes: 22 additions & 28 deletions src/containers/Navigation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,42 +41,36 @@ const Navigation = ({ sections, currentSlug }: Props): JSX.Element => {
const readSections: Set<NavigationSectionItem['slug']> = new Set();
// Assume section items up to the one currently open have been read. Track
// their unique slugs in `readSections` set.
Object.keys(sections).some(
(sectionKey): boolean => {
let isCurrentSlug = false;
sections[sectionKey].some(
(sectionItem): boolean => {
isCurrentSlug = sectionItem.slug === currentSlug;
if (!isCurrentSlug) {
readSections.add(sectionItem.slug);
}

return isCurrentSlug;
}
);
Object.keys(sections).some((sectionKey): boolean => {
let isCurrentSlug = false;
sections[sectionKey].some((sectionItem): boolean => {
isCurrentSlug = sectionItem.slug === currentSlug;
if (!isCurrentSlug) {
readSections.add(sectionItem.slug);
}

return isCurrentSlug;
}
);
});

return isCurrentSlug;
});

return (
<nav className={className} ref={navElement}>
<button type="button" className="side-nav__open" onClick={toggle}>
Menu
</button>
{Object.keys(sections).map(
(sectionKey: string): JSX.Element[] => (
<NavigationSection
key={sectionKey}
title={sectionKey}
section={sections[sectionKey]}
currentSlug={currentSlug}
onItemClick={onItemClick}
readSections={readSections}
autoScroll={autoScroll}
/>
)
)}
{Object.keys(sections).map((sectionKey: string): JSX.Element[] => (
<NavigationSection
key={sectionKey}
title={sectionKey}
section={sections[sectionKey]}
currentSlug={currentSlug}
onItemClick={onItemClick}
readSections={readSections}
autoScroll={autoScroll}
/>
))}
</nav>
);
};
Expand Down
25 changes: 11 additions & 14 deletions src/hooks/useApiDocs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,20 +92,17 @@ export function useApiData(version: string | null): APIResponse {
modules: [],
});

useEffect(
(): void => {
const fetchData = async (): Promise<void> => {
const res = await window.fetch(
`https://nodejs.org/dist/${version}/docs/api/all.json`
);
setApiData((await res.json()) as APIResponse);
};
if (version) {
fetchData();
}
},
[version]
);
useEffect((): void => {
const fetchData = async (): Promise<void> => {
const res = await window.fetch(
`https://nodejs.org/dist/${version}/docs/api/all.json`
);
setApiData((await res.json()) as APIResponse);
};
if (version) {
fetchData();
}
}, [version]);

return apiData;
}
16 changes: 8 additions & 8 deletions src/pages/docs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ function renderArticleOverview(
): JSX.Element[] {
const children: JSX.Element[] = [];
if (obj.events) {
obj.events.map(
(evt): JSX.Element[] => renderArticleOverview(evt, children)
obj.events.map((evt): JSX.Element[] =>
renderArticleOverview(evt, children)
);
}
if (obj.methods) {
obj.methods.map(
(method): JSX.Element[] => renderArticleOverview(method, children)
obj.methods.map((method): JSX.Element[] =>
renderArticleOverview(method, children)
);
}
if (obj.properties) {
Expand All @@ -40,8 +40,8 @@ function renderArticleOverview(
.map((prop): JSX.Element[] => renderArticleOverview(prop, children));
}
if (obj.classes) {
obj.classes.map(
(klass): JSX.Element[] => renderArticleOverview(klass, children)
obj.classes.map((klass): JSX.Element[] =>
renderArticleOverview(klass, children)
);
}

Expand Down Expand Up @@ -178,8 +178,8 @@ function renderArticle(page: ApiDocsObj | null): JSX.Element {
<ul className="api-key">
{renderArticleOverview(page)}
{page.modules &&
page.modules.map(
(mod): JSX.Element[] => renderArticleOverview(mod, [])
page.modules.map((mod): JSX.Element[] =>
renderArticleOverview(mod, [])
)}
</ul>
{page.desc && <p dangerouslySetInnerHTML={{ __html: page.desc }} />}
Expand Down
19 changes: 8 additions & 11 deletions src/util/konami.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,13 @@ if (typeof window !== `undefined`) {
})();

let discoMode: NodeJS.Timeout | null = null;
document.addEventListener(
'konamiCode',
(): void => {
if (discoMode) {
return clearInterval(discoMode);
}
discoMode = setInterval(
(): boolean => document.body.classList.toggle('dark-mode'),
300
);
document.addEventListener('konamiCode', (): void => {
if (discoMode) {
return clearInterval(discoMode);
}
);
discoMode = setInterval(
(): boolean => document.body.classList.toggle('dark-mode'),
300
);
});
}
36 changes: 17 additions & 19 deletions src/util/scrollTo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,23 @@ export function scrollTo(
let previousTime = window.performance.now();
let currentTime = 0;

return new Promise<boolean>(
(resolve): void => {
const animateScroll = (): void => {
const time = window.performance.now();
const increment = time - previousTime;
previousTime = time;
currentTime += increment;
(element || document.scrollingElement || window).scrollTo(
0,
easeInOutCubic(currentTime, start, change, duration)
);
if (currentTime < duration) {
window.requestAnimationFrame(animateScroll);
}
resolve(true);
};
animateScroll();
}
);
return new Promise<boolean>((resolve): void => {
const animateScroll = (): void => {
const time = window.performance.now();
const increment = time - previousTime;
previousTime = time;
currentTime += increment;
(element || document.scrollingElement || window).scrollTo(
0,
easeInOutCubic(currentTime, start, change, duration)
);
if (currentTime < duration) {
window.requestAnimationFrame(animateScroll);
}
resolve(true);
};
animateScroll();
});
}

const SPEED_MODIFIER = 0.9;
Expand Down