Skip to content

Commit

Permalink
DOP-4689: Implement multi-page tutorials (#1225)
Browse files Browse the repository at this point in the history
Co-authored-by: Caesar Bell <[email protected]>
  • Loading branch information
rayangler and Caesar Bell authored Sep 13, 2024
1 parent fd564e8 commit a452992
Show file tree
Hide file tree
Showing 27 changed files with 2,160 additions and 938 deletions.
16 changes: 4 additions & 12 deletions src/components/Contents/index.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import styled from '@emotion/styled';
import { theme } from '../../theme/docsTheme';
import { formatText } from '../../utils/format-text';
import { ContentsContext } from './contents-context';
import ContentsList from './ContentsList';
import ContentsListItem from './ContentsListItem';

const StyledContents = styled('div')`
@media ${theme.screenSize.largeAndUp} {
display: ${(props) => (props.displayOnDesktopOnly ? '' : 'none')};
}
`;

const formatTextOptions = {
literalEnableInline: true,
};

const Contents = ({ displayOnDesktopOnly }) => {
const Contents = ({ className }) => {
const { activeHeadingId, headingNodes, showContentsComponent } = useContext(ContentsContext);

if (headingNodes.length === 0 || !showContentsComponent) {
Expand All @@ -27,7 +19,7 @@ const Contents = ({ displayOnDesktopOnly }) => {
const label = 'On this page';

return (
<StyledContents displayOnDesktopOnly={displayOnDesktopOnly}>
<div className={className}>
<ContentsList label={label}>
{headingNodes.map(({ depth, id, title }) => {
// Depth of heading nodes refers to their depth in the AST
Expand All @@ -39,12 +31,12 @@ const Contents = ({ displayOnDesktopOnly }) => {
);
})}
</ContentsList>
</StyledContents>
</div>
);
};

Contents.propTypes = {
displayOnDesktopOnly: PropTypes.bool,
className: PropTypes.string,
};

export default Contents;
2 changes: 1 addition & 1 deletion src/components/DocumentBody.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ const DocumentBody = (props) => {
>
<ImageContextProvider images={props.data?.pageImage?.images ?? []}>
<FootnoteContext.Provider value={{ footnotes }}>
<PageContext.Provider value={{ page, template, slug }}>
<PageContext.Provider value={{ page, template, slug, options: page?.options }}>
<div id="template-container">
<Template {...props} useChatbot={useChatbot}>
{pageNodes.map((child, index) => (
Expand Down
17 changes: 16 additions & 1 deletion src/components/Heading.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import Button from '@leafygreen-ui/button';
import Icon from '@leafygreen-ui/icon';
import useScreenSize from '../hooks/useScreenSize';
import { usePageContext } from '../context/page-context';
import { theme } from '../theme/docsTheme';
import ComponentFactory from './ComponentFactory';
import TabSelectors from './Tabs/TabSelectors';
import { TabContext } from './Tabs/tab-context';
import { InstruqtContext } from './Instruqt/instruqt-context';
import ConditionalWrapper from './ConditionalWrapper';
import Contents from './Contents';
import Permalink from './Permalink';
import { TimeRequired } from './MultiPageTutorials';

const h2Styling = css`
margin-top: 16px;
Expand All @@ -30,6 +32,14 @@ const labButtonStyling = css`
margin-left: 18px;
`;

const contentsStyle = css`
margin-top: ${theme.size.medium};
@media ${theme.screenSize.largeAndUp} {
display: none;
}
`;

const determineHeading = (sectionDepth) => {
if (sectionDepth === 1) {
return H2;
Expand Down Expand Up @@ -93,7 +103,12 @@ const Heading = ({ sectionDepth, nodeData, className, ...rest }) => {
)}
</HeadingTag>
</ConditionalWrapper>
{isPageTitle && <Contents />}
{isPageTitle && (
<>
<TimeRequired />
<Contents className={contentsStyle} />
</>
)}
</>
);
};
Expand Down
21 changes: 21 additions & 0 deletions src/components/Internal/Overline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import PropTypes from 'prop-types';
import { css, cx } from '@leafygreen-ui/emotion';
import { Overline as LGOverline } from '@leafygreen-ui/typography';

const overlineBaseStyling = css`
margin-top: 48px;
margin-bottom: 0px;
color: var(--font-color-light);
`;

const Overline = ({ className, children }) => {
return <LGOverline className={cx(overlineBaseStyling, className)}>{children}</LGOverline>;
};

Overline.propTypes = {
className: PropTypes.string,
children: PropTypes.node,
};

export default Overline;
122 changes: 0 additions & 122 deletions src/components/InternalPageNav.js

This file was deleted.

110 changes: 110 additions & 0 deletions src/components/InternalPageNav/InternalPageNav.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React from 'react';
import PropTypes from 'prop-types';
import { glyphs } from '@leafygreen-ui/icon';
import { css, cx } from '@leafygreen-ui/emotion';
import { theme } from '../../theme/docsTheme';
import { getPageTitle } from '../../utils/get-page-title';
import { useActiveMpTutorial } from '../MultiPageTutorials';
import { reportAnalytics } from '../../utils/report-analytics';
import NextPrevLink from './NextPrevLink';

const containerStyling = css`
padding-bottom: 2.5em;
width: 100%;
display: flex;
justify-content: space-between;
column-gap: ${theme.size.default};
margin-top: 88px;
@media ${theme.screenSize.upToSmall} {
flex-direction: column-reverse;
row-gap: 64px;
margin-top: 66px;
}
@media print {
display: none;
}
`;

const getActiveTutorialPage = (activeTutorial, key, linkTitle) => {
return {
targetSlug: activeTutorial[key].targetSlug,
pageTitle: activeTutorial[key].pageTitle,
linkTitle,
};
};

const getTocPage = (targetSlug, slugTitleMapping, linkTitle) => {
return {
targetSlug,
pageTitle: targetSlug ? getPageTitle(targetSlug, slugTitleMapping) : null,
linkTitle,
};
};

const getPrev = (activeTutorial, toctreeOrder, slugTitleMapping, slugIndex) => {
const key = 'prev';
if (activeTutorial?.[key]) {
return getActiveTutorialPage(activeTutorial, key, 'Previous Step');
}
const prevSlug = slugIndex > 0 ? toctreeOrder[slugIndex - 1] : null;
return getTocPage(prevSlug, slugTitleMapping, 'Previous Section');
};

const getNext = (activeTutorial, toctreeOrder, slugTitleMapping, slugIndex) => {
const key = 'next';
if (activeTutorial?.[key]) {
return getActiveTutorialPage(activeTutorial, key, 'Next Step');
}
const nextSlug = slugIndex < toctreeOrder.length - 1 ? toctreeOrder[slugIndex + 1] : null;
return getTocPage(nextSlug, slugTitleMapping, 'Next Section');
};

const InternalPageNav = ({ slug, slugTitleMapping, toctreeOrder }) => {
const activeTutorial = useActiveMpTutorial();
const slugIndex = toctreeOrder.indexOf(slug);
const prevPage = getPrev(activeTutorial, toctreeOrder, slugTitleMapping, slugIndex);
const nextPage = getNext(activeTutorial, toctreeOrder, slugTitleMapping, slugIndex);

const handleClick = (direction, targetSlug) => {
reportAnalytics('InternalPageNavClicked', {
direction,
targetSlug,
});
};

return (
<div className={cx(containerStyling)}>
{prevPage?.targetSlug && (
<NextPrevLink
icon={glyphs.ArrowLeft.displayName}
direction="Back"
targetSlug={prevPage.targetSlug}
pageTitle={prevPage.pageTitle}
title={prevPage.linkTitle}
onClick={handleClick}
/>
)}
{nextPage?.targetSlug && (
<NextPrevLink
icon={glyphs.ArrowRight.displayName}
direction="Next"
targetSlug={nextPage.targetSlug}
pageTitle={nextPage.pageTitle}
title={nextPage.linkTitle}
onClick={handleClick}
/>
)}
</div>
);
};

InternalPageNav.propTypes = {
slug: PropTypes.string.isRequired,
slugTitleMapping: PropTypes.objectOf(PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.string]))
.isRequired,
toctreeOrder: PropTypes.arrayOf(PropTypes.string).isRequired,
};

export default InternalPageNav;
Loading

0 comments on commit a452992

Please sign in to comment.