docs(core): add scroll_25, scroll_50, scroll_75, and scroll_90 events to track engagement (#27461)

This PR adds events to track engagement in our docs. Since we use a
scrollable `<div>` in our docs, the normal `scroll` events in GA do not
work.

A new `<ScrollableContent>` component is added that will do two things:
- Send `scroll_25`, `scroll_50`, `scroll_75`, and `scroll_90` events
whenever the user scrolls to 25%, 50%, 75%, of 90% of the content
- Optionally reset scroll top to zero whenever router changes (existing
behavior)

All of the places where we have content in a scrollable `<div>` is
replaced with `<ScrollableContent>`.

Note: 90% means user has reached the bottom, since it's not usually
possible to get to 100%.
This commit is contained in:
Jack Hsu 2024-08-16 12:25:20 -04:00 committed by GitHub
parent b699207070
commit 9dca7c7025
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 300 additions and 659 deletions

View File

@ -4,13 +4,12 @@ import { ProcessedDocument, RelatedDocument } from '@nx/nx-dev/models-document';
import { MenuItem } from '@nx/nx-dev/models-menu';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { GetStaticPaths, GetStaticProps } from 'next';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { menusApi } from '../lib/menus.api';
import { useNavToggle } from '../lib/navigation-toggle.effect';
import { nxDocumentationApi } from '../lib/nx.api';
import { tagsApi } from '../lib/tags.api';
import { fetchGithubStarCount } from '../lib/githubStars.api';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function NxDocumentation({
document,
@ -23,25 +22,7 @@ export default function NxDocumentation({
relatedDocuments: RelatedDocument[];
widgetData: { githubStarsCount: number };
}) {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const menuWithSections = {
sections: [getBasicNxSection(menu)],
@ -62,18 +43,13 @@ export default function NxDocumentation({
toggleNav={toggleNav}
navIsOpen={navIsOpen}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<DocViewer
document={document}
relatedDocuments={relatedDocuments}
widgetData={widgetData}
/>
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -4,13 +4,12 @@ import { ProcessedDocument, RelatedDocument } from '@nx/nx-dev/models-document';
import { Menu, MenuItem } from '@nx/nx-dev/models-menu';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { GetStaticPaths, GetStaticProps } from 'next';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { ciApi } from '../../lib/ci.api';
import { menusApi } from '../../lib/menus.api';
import { useNavToggle } from '../../lib/navigation-toggle.effect';
import { tagsApi } from '../../lib/tags.api';
import { fetchGithubStarCount } from '../../lib/githubStars.api';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function Pages({
document,
@ -23,25 +22,7 @@ export default function Pages({
relatedDocuments: RelatedDocument[];
widgetData: { githubStarsCount: number };
}) {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: {
document: ProcessedDocument;
@ -70,18 +51,13 @@ export default function Pages({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<DocViewer
document={vm.document}
relatedDocuments={vm.relatedDocuments}
widgetData={widgetData}
/>
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -4,13 +4,12 @@ import { ProcessedDocument, RelatedDocument } from '@nx/nx-dev/models-document';
import { Menu, MenuItem } from '@nx/nx-dev/models-menu';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { GetStaticProps } from 'next';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { ciApi } from '../../lib/ci.api';
import { menusApi } from '../../lib/menus.api';
import { useNavToggle } from '../../lib/navigation-toggle.effect';
import { tagsApi } from '../../lib/tags.api';
import { fetchGithubStarCount } from '../../lib/githubStars.api';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function CloudRoot({
document,
@ -23,25 +22,7 @@ export default function CloudRoot({
relatedDocuments: RelatedDocument[];
widgetData: { githubStarsCount: number };
}) {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: {
document: ProcessedDocument;
@ -70,18 +51,13 @@ export default function CloudRoot({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<DocViewer
document={document}
relatedDocuments={vm.relatedDocuments}
widgetData={widgetData}
/>
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -11,6 +11,7 @@ import { useNavToggle } from '../../lib/navigation-toggle.effect';
import { nxPluginsApi } from '../../lib/plugins.api';
import { tagsApi } from '../../lib/tags.api';
import { fetchGithubStarCount } from '../../lib/githubStars.api';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function Pages({
document,
@ -23,25 +24,7 @@ export default function Pages({
relatedDocuments: RelatedDocument[];
widgetData: { githubStarsCount: number };
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: {
document: ProcessedDocument;
@ -70,18 +53,13 @@ export default function Pages({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<DocViewer
document={vm.document}
relatedDocuments={vm.relatedDocuments}
widgetData={widgetData}
/>
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -4,13 +4,12 @@ import { ProcessedDocument, RelatedDocument } from '@nx/nx-dev/models-document';
import { Menu, MenuItem } from '@nx/nx-dev/models-menu';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { GetStaticProps } from 'next';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { menusApi } from '../../lib/menus.api';
import { useNavToggle } from '../../lib/navigation-toggle.effect';
import { nxPluginsApi } from '../../lib/plugins.api';
import { tagsApi } from '../../lib/tags.api';
import { fetchGithubStarCount } from '../../lib/githubStars.api';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function PluginsRoot({
document,
@ -23,25 +22,7 @@ export default function PluginsRoot({
relatedDocuments: RelatedDocument[];
widgetData: { githubStarsCount: number };
}) {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: {
document: ProcessedDocument;
@ -70,18 +51,13 @@ export default function PluginsRoot({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<DocViewer
document={document}
relatedDocuments={vm.relatedDocuments}
widgetData={widgetData}
/>
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -7,13 +7,12 @@ import { Menu, MenuItem, MenuSection } from '@nx/nx-dev/models-menu';
import { ProcessedPackageMetadata } from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { GetStaticPaths } from 'next';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { menusApi } from '../../../../lib/menus.api';
import { useNavToggle } from '../../../../lib/navigation-toggle.effect';
import { nxPackagesApi } from '../../../../lib/packages.api';
import { tagsApi } from '../../../../lib/tags.api';
import { fetchGithubStarCount } from '../../../../lib/githubStars.api';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function PackageDocument({
document,
@ -27,25 +26,7 @@ export default function PackageDocument({
relatedDocuments: RelatedDocument[];
widgetData: { githubStarsCount: number };
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: {
document: ProcessedDocument;
@ -77,18 +58,13 @@ export default function PackageDocument({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<DocViewer
document={vm.document}
relatedDocuments={vm.relatedDocuments}
widgetData={widgetData}
/>
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -4,12 +4,11 @@ import { Menu, MenuItem, MenuSection } from '@nx/nx-dev/models-menu';
import { ProcessedPackageMetadata } from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { GetStaticPaths } from 'next';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { PackageSchemaSubList } from '@nx/nx-dev/feature-package-schema-viewer/src/lib/package-schema-sub-list';
import { menusApi } from '../../../../lib/menus.api';
import { useNavToggle } from '../../../../lib/navigation-toggle.effect';
import { nxPackagesApi } from '../../../../lib/packages.api';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function DocumentsIndex({
menu,
@ -18,25 +17,7 @@ export default function DocumentsIndex({
menu: MenuItem[];
pkg: ProcessedPackageMetadata;
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: { menu: Menu; package: ProcessedPackageMetadata } = {
menu: {
@ -69,14 +50,9 @@ export default function DocumentsIndex({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<PackageSchemaSubList pkg={vm.package} type={'document'} />
</div>
</ScrollableContent>
</main>
</div>
);
@ -92,6 +68,7 @@ export const getStaticPaths: GetStaticPaths = () => {
fallback: 'blocking',
};
};
export async function getStaticProps({
params,
}: {

View File

@ -8,11 +8,10 @@ import {
} from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { GetStaticPaths } from 'next';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { menusApi } from '../../../../lib/menus.api';
import { useNavToggle } from '../../../../lib/navigation-toggle.effect';
import { nxPackagesApi } from '../../../../lib/packages.api';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function PackageExecutor({
menu,
@ -23,25 +22,7 @@ export default function PackageExecutor({
pkg: ProcessedPackageMetadata;
schema: SchemaMetadata;
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: {
menu: Menu;
@ -79,14 +60,9 @@ export default function PackageExecutor({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<PackageSchemaViewer pkg={vm.package} schema={vm.schema} />
</div>
</ScrollableContent>
</main>
</div>
);
@ -124,6 +100,7 @@ function getData(
menu: menusApi.getMenu('nx-api', 'nx-api'),
};
}
export async function getStaticProps({
params,
}: {

View File

@ -4,12 +4,11 @@ import { Menu, MenuItem, MenuSection } from '@nx/nx-dev/models-menu';
import { ProcessedPackageMetadata } from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { GetStaticPaths } from 'next';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { PackageSchemaSubList } from '@nx/nx-dev/feature-package-schema-viewer/src/lib/package-schema-sub-list';
import { menusApi } from '../../../../lib/menus.api';
import { useNavToggle } from '../../../../lib/navigation-toggle.effect';
import { nxPackagesApi } from '../../../../lib/packages.api';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function ExecutorsIndex({
menu,
@ -18,25 +17,7 @@ export default function ExecutorsIndex({
menu: MenuItem[];
pkg: ProcessedPackageMetadata;
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: { menu: Menu; package: ProcessedPackageMetadata } = {
menu: {
@ -69,14 +50,9 @@ export default function ExecutorsIndex({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<PackageSchemaSubList pkg={vm.package} type={'executor'} />
</div>
</ScrollableContent>
</main>
</div>
);
@ -92,6 +68,7 @@ export const getStaticPaths: GetStaticPaths = () => {
fallback: 'blocking',
};
};
export async function getStaticProps({
params,
}: {

View File

@ -8,11 +8,10 @@ import {
} from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { GetStaticPaths } from 'next';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { menusApi } from '../../../../lib/menus.api';
import { useNavToggle } from '../../../../lib/navigation-toggle.effect';
import { nxPackagesApi } from '../../../../lib/packages.api';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function PackageGenerator({
menu,
@ -23,26 +22,7 @@ export default function PackageGenerator({
pkg: ProcessedPackageMetadata;
schema: SchemaMetadata;
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: {
menu: Menu;
package: ProcessedPackageMetadata;
@ -79,14 +59,9 @@ export default function PackageGenerator({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<PackageSchemaViewer pkg={vm.package} schema={vm.schema} />
</div>
</ScrollableContent>
</main>
</div>
);
@ -124,6 +99,7 @@ function getData(
menu: menusApi.getMenu('nx-api', 'nx-api'),
};
}
export async function getStaticProps({
params,
}: {

View File

@ -4,12 +4,11 @@ import { Menu, MenuItem, MenuSection } from '@nx/nx-dev/models-menu';
import { ProcessedPackageMetadata } from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { GetStaticPaths } from 'next';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { PackageSchemaSubList } from '@nx/nx-dev/feature-package-schema-viewer/src/lib/package-schema-sub-list';
import { menusApi } from '../../../../lib/menus.api';
import { useNavToggle } from '../../../../lib/navigation-toggle.effect';
import { nxPackagesApi } from '../../../../lib/packages.api';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function GeneratorsIndex({
menu,
@ -18,25 +17,7 @@ export default function GeneratorsIndex({
menu: MenuItem[];
pkg: ProcessedPackageMetadata;
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: { menu: Menu; package: ProcessedPackageMetadata } = {
menu: {
@ -69,14 +50,9 @@ export default function GeneratorsIndex({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<PackageSchemaSubList pkg={vm.package} type={'generator'} />
</div>
</ScrollableContent>
</main>
</div>
);
@ -92,6 +68,7 @@ export const getStaticPaths: GetStaticPaths = () => {
fallback: 'blocking',
};
};
export async function getStaticProps({
params,
}: {

View File

@ -6,12 +6,11 @@ import { Menu, MenuItem, MenuSection } from '@nx/nx-dev/models-menu';
import { ProcessedPackageMetadata } from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { GetStaticPaths } from 'next';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { menusApi } from '../../../lib/menus.api';
import { useNavToggle } from '../../../lib/navigation-toggle.effect';
import { nxPackagesApi } from '../../../lib/packages.api';
import { tagsApi } from '../../../lib/tags.api';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function Package({
overview,
@ -22,25 +21,7 @@ export default function Package({
overview: string;
pkg: ProcessedPackageMetadata;
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: { menu: Menu; package: ProcessedPackageMetadata } = {
menu: {
@ -73,14 +54,9 @@ export default function Package({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<PackageSchemaList pkg={vm.package} overview={overview} />
</div>
</ScrollableContent>
</main>
</div>
);
@ -129,6 +105,7 @@ function getData(packageName: string): {
pkg,
};
}
export async function getStaticProps({ params }: { params: { name: string } }) {
try {
return { props: getData(params.name) };

View File

@ -20,6 +20,7 @@ import { useMemo } from 'react';
import { menusApi } from '../../lib/menus.api';
import { useNavToggle } from '../../lib/navigation-toggle.effect';
import { nxPackagesApi } from '../../lib/packages.api';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function Packages({
packages,
@ -97,11 +98,7 @@ export default function Packages({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent>
<div className="mx-auto w-full grow items-stretch px-4 sm:px-6 lg:px-8 2xl:max-w-6xl">
<div id="content-wrapper" className="w-full flex-auto flex-col">
<div className="mb-6 pt-8">
@ -152,7 +149,7 @@ export default function Packages({
</div>
</div>
<Footer />
</div>
</ScrollableContent>
</main>
</div>
</>

View File

@ -3,12 +3,11 @@ import { sortCorePackagesFirst } from '@nx/nx-dev/data-access-packages';
import { Menu, MenuItem, MenuSection } from '@nx/nx-dev/models-menu';
import { ProcessedPackageMetadata } from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { PackageSchemaSubList } from '@nx/nx-dev/feature-package-schema-viewer/src/lib/package-schema-sub-list';
import { menusApi } from '../../../../lib/menus.api';
import { useNavToggle } from '../../../../lib/navigation-toggle.effect';
import { pkg } from '../../../../lib/rspack/pkg';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function DocumentsIndex({
menu,
@ -17,25 +16,7 @@ export default function DocumentsIndex({
menu: MenuItem[];
pkg: ProcessedPackageMetadata;
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: { menu: Menu; package: ProcessedPackageMetadata } = {
menu: {
@ -68,14 +49,9 @@ export default function DocumentsIndex({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<PackageSchemaSubList pkg={vm.package} type={'document'} />
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -5,13 +5,12 @@ import { ProcessedDocument, RelatedDocument } from '@nx/nx-dev/models-document';
import { Menu, MenuItem, MenuSection } from '@nx/nx-dev/models-menu';
import { ProcessedPackageMetadata } from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { menusApi } from '../../../../lib/menus.api';
import { useNavToggle } from '../../../../lib/navigation-toggle.effect';
import { content } from '../../../../lib/rspack/content/overview';
import { pkg } from '../../../../lib/rspack/pkg';
import { fetchGithubStarCount } from '../../../../lib/githubStars.api';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function Overview({
document,
@ -25,25 +24,7 @@ export default function Overview({
relatedDocuments: RelatedDocument[];
widgetData: { githubStarsCount: number };
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: {
document: ProcessedDocument;
@ -75,18 +56,13 @@ export default function Overview({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<DocViewer
document={vm.document}
relatedDocuments={vm.relatedDocuments}
widgetData={widgetData}
/>
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -5,13 +5,12 @@ import { ProcessedDocument, RelatedDocument } from '@nx/nx-dev/models-document';
import { Menu, MenuItem, MenuSection } from '@nx/nx-dev/models-menu';
import { ProcessedPackageMetadata } from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { menusApi } from '../../../../lib/menus.api';
import { useNavToggle } from '../../../../lib/navigation-toggle.effect';
import { content } from '../../../../lib/rspack/content/rspack-config-setup';
import { pkg } from '../../../../lib/rspack/pkg';
import { fetchGithubStarCount } from '../../../../lib/githubStars.api';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function RspackConfigSetup({
document,
@ -25,25 +24,7 @@ export default function RspackConfigSetup({
relatedDocuments: RelatedDocument[];
widgetData: { githubStarsCount: number };
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: {
document: ProcessedDocument;
@ -75,18 +56,13 @@ export default function RspackConfigSetup({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<DocViewer
document={vm.document}
relatedDocuments={vm.relatedDocuments}
widgetData={widgetData}
/>
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -5,13 +5,12 @@ import { ProcessedDocument, RelatedDocument } from '@nx/nx-dev/models-document';
import { Menu, MenuItem, MenuSection } from '@nx/nx-dev/models-menu';
import { ProcessedPackageMetadata } from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { menusApi } from '../../../../lib/menus.api';
import { useNavToggle } from '../../../../lib/navigation-toggle.effect';
import { content } from '../../../../lib/rspack/content/rspack-plugin';
import { pkg } from '../../../../lib/rspack/pkg';
import { fetchGithubStarCount } from '../../../../lib/githubStars.api';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function RspackPlugins({
document,
@ -25,25 +24,7 @@ export default function RspackPlugins({
relatedDocuments: RelatedDocument[];
widgetData: { githubStarsCount: number };
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: {
document: ProcessedDocument;
@ -75,18 +56,13 @@ export default function RspackPlugins({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<DocViewer
document={vm.document}
relatedDocuments={vm.relatedDocuments}
widgetData={widgetData}
/>
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -7,12 +7,11 @@ import {
SchemaMetadata,
} from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { menusApi } from '../../../../lib/menus.api';
import { useNavToggle } from '../../../../lib/navigation-toggle.effect';
import { schema } from '../../../../lib/rspack/schema/executors/dev-server';
import { pkg } from '../../../../lib/rspack/pkg';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function DevServerExecutor({
menu,
@ -23,25 +22,7 @@ export default function DevServerExecutor({
pkg: ProcessedPackageMetadata;
schema: SchemaMetadata;
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: {
menu: Menu;
@ -79,14 +60,9 @@ export default function DevServerExecutor({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<PackageSchemaViewer pkg={vm.package} schema={vm.schema} />
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -3,12 +3,11 @@ import { sortCorePackagesFirst } from '@nx/nx-dev/data-access-packages';
import { Menu, MenuItem, MenuSection } from '@nx/nx-dev/models-menu';
import { ProcessedPackageMetadata } from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { PackageSchemaSubList } from '@nx/nx-dev/feature-package-schema-viewer/src/lib/package-schema-sub-list';
import { menusApi } from '../../../../lib/menus.api';
import { useNavToggle } from '../../../../lib/navigation-toggle.effect';
import { pkg } from '../../../../lib/rspack/pkg';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function ExecutorsIndex({
menu,
@ -17,25 +16,7 @@ export default function ExecutorsIndex({
menu: MenuItem[];
pkg: ProcessedPackageMetadata;
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: { menu: Menu; package: ProcessedPackageMetadata } = {
menu: {
@ -68,14 +49,9 @@ export default function ExecutorsIndex({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<PackageSchemaSubList pkg={vm.package} type={'executor'} />
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -7,12 +7,11 @@ import {
SchemaMetadata,
} from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { menusApi } from '../../../../lib/menus.api';
import { useNavToggle } from '../../../../lib/navigation-toggle.effect';
import { schema } from '../../../../lib/rspack/schema/executors/rspack';
import { pkg } from '../../../../lib/rspack/pkg';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function RspackExecutor({
menu,
@ -23,25 +22,7 @@ export default function RspackExecutor({
pkg: ProcessedPackageMetadata;
schema: SchemaMetadata;
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: {
menu: Menu;
@ -79,14 +60,9 @@ export default function RspackExecutor({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<PackageSchemaViewer pkg={vm.package} schema={vm.schema} />
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -7,12 +7,11 @@ import {
SchemaMetadata,
} from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { menusApi } from '../../../../lib/menus.api';
import { useNavToggle } from '../../../../lib/navigation-toggle.effect';
import { schema } from '../../../../lib/rspack/schema/generators/application';
import { pkg } from '../../../../lib/rspack/pkg';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function ApplicationGenerator({
menu,
@ -23,25 +22,7 @@ export default function ApplicationGenerator({
pkg: ProcessedPackageMetadata;
schema: SchemaMetadata;
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: {
menu: Menu;
@ -79,14 +60,9 @@ export default function ApplicationGenerator({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<PackageSchemaViewer pkg={vm.package} schema={vm.schema} />
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -7,12 +7,11 @@ import {
SchemaMetadata,
} from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { menusApi } from '../../../../lib/menus.api';
import { useNavToggle } from '../../../../lib/navigation-toggle.effect';
import { schema } from '../../../../lib/rspack/schema/generators/configuration';
import { pkg } from '../../../../lib/rspack/pkg';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function ConfigurationGenerator({
menu,
@ -23,25 +22,7 @@ export default function ConfigurationGenerator({
pkg: ProcessedPackageMetadata;
schema: SchemaMetadata;
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: {
menu: Menu;
@ -79,14 +60,9 @@ export default function ConfigurationGenerator({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<PackageSchemaViewer pkg={vm.package} schema={vm.schema} />
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -3,12 +3,11 @@ import { sortCorePackagesFirst } from '@nx/nx-dev/data-access-packages';
import { Menu, MenuItem, MenuSection } from '@nx/nx-dev/models-menu';
import { ProcessedPackageMetadata } from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { PackageSchemaSubList } from '@nx/nx-dev/feature-package-schema-viewer/src/lib/package-schema-sub-list';
import { menusApi } from '../../../../lib/menus.api';
import { useNavToggle } from '../../../../lib/navigation-toggle.effect';
import { pkg } from '../../../../lib/rspack/pkg';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function GeneratorsIndex({
menu,
@ -17,25 +16,7 @@ export default function GeneratorsIndex({
menu: MenuItem[];
pkg: ProcessedPackageMetadata;
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: { menu: Menu; package: ProcessedPackageMetadata } = {
menu: {
@ -68,14 +49,9 @@ export default function GeneratorsIndex({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<PackageSchemaSubList pkg={vm.package} type={'generator'} />
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -7,12 +7,11 @@ import {
SchemaMetadata,
} from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { menusApi } from '../../../../lib/menus.api';
import { useNavToggle } from '../../../../lib/navigation-toggle.effect';
import { schema } from '../../../../lib/rspack/schema/generators/init';
import { pkg } from '../../../../lib/rspack/pkg';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function InitGenerator({
menu,
@ -23,25 +22,7 @@ export default function InitGenerator({
pkg: ProcessedPackageMetadata;
schema: SchemaMetadata;
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: {
menu: Menu;
@ -79,14 +60,9 @@ export default function InitGenerator({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<PackageSchemaViewer pkg={vm.package} schema={vm.schema} />
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -4,12 +4,11 @@ import { sortCorePackagesFirst } from '@nx/nx-dev/data-access-packages';
import { Menu, MenuItem, MenuSection } from '@nx/nx-dev/models-menu';
import { ProcessedPackageMetadata } from '@nx/nx-dev/models-package';
import { DocumentationHeader, SidebarContainer } from '@nx/nx-dev/ui-common';
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import { menusApi } from '../../../lib/menus.api';
import { useNavToggle } from '../../../lib/navigation-toggle.effect';
import { content } from '../../../lib/rspack/content/overview';
import { pkg } from '../../../lib/rspack/pkg';
import { ScrollableContent } from '@nx/ui-scrollable-content';
export default function RspackIndex({
overview,
@ -20,25 +19,7 @@ export default function RspackIndex({
overview: string;
pkg: ProcessedPackageMetadata;
}): JSX.Element {
const router = useRouter();
const { toggleNav, navIsOpen } = useNavToggle();
const wrapperElement = useRef(null);
useEffect(() => {
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement) return;
(wrapperElement as any).current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [router, wrapperElement]);
const vm: { menu: Menu; package: ProcessedPackageMetadata } = {
menu: {
@ -71,14 +52,9 @@ export default function RspackIndex({
navIsOpen={navIsOpen}
toggleNav={toggleNav}
/>
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent resetScrollOnNavigation={true}>
<PackageSchemaList pkg={vm.package} overview={overview} />
</div>
</ScrollableContent>
</main>
</div>
);

View File

@ -12,6 +12,7 @@ import { useRouter } from 'next/router';
import { menusApi } from '../lib/menus.api';
import { useNavToggle } from '../lib/navigation-toggle.effect';
import { nxPackagesApi } from '../lib/packages.api';
import { ScrollableContent } from '@nx/ui-scrollable-content';
declare const fetch: any;
let qualityIndicators = require('./quality-indicators.json');
@ -112,11 +113,7 @@ export default function Browse(props: BrowseProps): JSX.Element {
toggleNav={toggleNav}
/>
</div>
<div
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
>
<ScrollableContent>
<div className="mx-auto w-full grow items-stretch px-4 sm:px-6 lg:px-8 2xl:max-w-6xl">
<div id="content-wrapper" className="w-full flex-auto flex-col">
<div className="mb-6 pt-8">
@ -141,7 +138,7 @@ export default function Browse(props: BrowseProps): JSX.Element {
</div>
<Footer />
</div>
</ScrollableContent>
</main>
</div>
</>

View File

@ -0,0 +1,12 @@
{
"presets": [
[
"@nx/react/babel",
{
"runtime": "automatic",
"useBuiltIns": "usage"
}
]
],
"plugins": []
}

View File

@ -0,0 +1,18 @@
{
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}

View File

@ -0,0 +1,7 @@
# ui-scrollable-content
This library was generated with [Nx](https://nx.dev).
## Running unit tests
Run `nx test ui-scrollable-content` to execute the unit tests via [Jest](https://jestjs.io).

View File

@ -0,0 +1,9 @@
/* eslint-disable */
export default {
displayName: 'nx-dev-ui-scrollable-content',
transform: {
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/next/babel'] }],
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/nx-dev/ui-scrollable-content',
};

View File

@ -0,0 +1,8 @@
{
"name": "nx-dev-ui-scrollable-content",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "nx-dev/ui-scrollable-content/src",
"projectType": "library",
"tags": ["scope:nx-dev", "type:ui"],
"targets": {}
}

View File

@ -0,0 +1 @@
export * from './lib/scrollable-content';

View File

@ -0,0 +1,84 @@
import type { JSX, ReactNode, UIEvent } from 'react';
import { useEffect, useRef } from 'react';
import { useRouter } from 'next/router';
import { sendCustomEvent } from '@nx/nx-dev/feature-analytics';
interface ScrollViewProps {
children?: ReactNode;
resetScrollOnNavigation?: boolean;
}
// Takes in a percentage like 0.33 and rounds to the nearest 0, 25%, 50%, 75%, 90% bucket.
function getScrollDepth(pct: number): 0 | 25 | 50 | 75 | 90 {
// Anything greater than 0.9 is just 90% and counts as reaching the bottom.
if (pct >= 0.9) {
return 90;
}
// Otherwise, divide into quarters (0, 25, 50, 75).
if (pct < 0.25) return 0;
if (pct < 0.5) return 25;
if (pct < 0.75) return 50;
return 75;
}
export function ScrollableContent(props: ScrollViewProps): JSX.Element {
const wrapperElement = useRef<HTMLDivElement | null>(null);
const router = useRouter();
const scrollDepth = useRef(0);
const shouldTrackScroll = useRef(true);
useEffect(() => {
if (!props.resetScrollOnNavigation) {
scrollDepth.current = 0;
return;
}
shouldTrackScroll.current = false;
setTimeout(() => {
scrollDepth.current = 0;
shouldTrackScroll.current = true;
}, 1000);
const handleRouteChange = (url: string) => {
if (url.includes('#')) return;
if (!wrapperElement.current) return;
wrapperElement.current.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [props.resetScrollOnNavigation, router, wrapperElement]);
const handleScroll = (evt: UIEvent<HTMLDivElement>) => {
if (!shouldTrackScroll.current) return;
const el = evt.currentTarget;
const { scrollHeight, scrollTop, offsetHeight } = el;
const depth = getScrollDepth((scrollTop + offsetHeight) / scrollHeight);
// Only track changes that are greater than the previous scroll depth.
// If a user already viewed 90% of the page we don't need to know they went back to 50%.
if (depth > scrollDepth.current) {
scrollDepth.current = depth;
sendCustomEvent(`scroll_${depth}`, 'scroll', router.asPath);
}
};
return (
<div
ref={wrapperElement}
id="wrapper"
data-testid="wrapper"
className="relative flex flex-grow flex-col items-stretch justify-start overflow-y-scroll"
onScroll={handleScroll}
>
{props.children}
</div>
);
}
export default ScrollableContent;

View File

@ -0,0 +1,15 @@
import { getScrollDepth } from './scrollable.util';
describe('getScrollDepth', () => {
it('should return in buckets of 25, 50, 75, and 90 percentages', () => {
expect(getScrollDepth(0)).toEqual(0);
expect(getScrollDepth(0.24)).toEqual(0);
expect(getScrollDepth(0.25)).toEqual(25);
expect(getScrollDepth(0.49)).toEqual(25);
expect(getScrollDepth(0.5)).toEqual(50);
expect(getScrollDepth(0.74)).toEqual(50);
expect(getScrollDepth(0.75)).toEqual(75);
expect(getScrollDepth(0.9)).toEqual(90);
expect(getScrollDepth(1)).toEqual(90);
});
});

View File

@ -0,0 +1,15 @@
/**
* Takes in a percentage like 0.33 and rounds to the nearest 0, 25%, 50%, 75%, 90% bucket.
*/
export function getScrollDepth(pct: number): 0 | 25 | 50 | 75 | 90 {
// Anything greater than 0.9 is just 90% and counts as reaching the bottom.
if (pct >= 0.9) {
return 90;
}
// Otherwise, divide into quarters (0, 25, 50, 75).
if (pct < 0.25) return 0;
if (pct < 0.5) return 25;
if (pct < 0.75) return 50;
return 75;
}

View File

@ -0,0 +1,21 @@
{
"compilerOptions": {
"jsx": "react-jsx",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"lib": ["dom"]
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
}
],
"extends": "../../tsconfig.base.json"
}

View File

@ -0,0 +1,23 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": [
"node",
"@nx/react/typings/cssmodule.d.ts",
"@nx/react/typings/image.d.ts"
]
},
"exclude": [
"jest.config.ts",
"src/**/*.spec.ts",
"src/**/*.test.ts",
"src/**/*.spec.tsx",
"src/**/*.test.tsx",
"src/**/*.spec.js",
"src/**/*.test.js",
"src/**/*.spec.jsx",
"src/**/*.test.jsx"
],
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
}

View File

@ -130,6 +130,9 @@
"@nx/storybook": ["packages/storybook"],
"@nx/storybook/*": ["packages/storybook/*"],
"@nx/typedoc-theme": ["typedoc-theme/src/index.ts"],
"@nx/ui-scrollable-content": [
"nx-dev/ui-scrollable-content/src/index.ts"
],
"@nx/vite": ["packages/vite"],
"@nx/vite/*": ["packages/vite/*"],
"@nx/vue": ["packages/vue"],