Skip to content

Commit

Permalink
Hide "On this page" on narrow viewports
Browse files Browse the repository at this point in the history
- Remove collapsed functionality from InPageTOC
- Dramatically simplify DocsScreen layout
    - No longer need to shift InPageTOC from between title & content to right rail
  • Loading branch information
kylegach committed Nov 16, 2023
1 parent 14baf60 commit 5411a51
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 142 deletions.
16 changes: 0 additions & 16 deletions src/components/basics/InPageTOC.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as React from 'react';

import { userEvent, within } from '@storybook/testing-library';
import { InPageTOC } from './InPageTOC';

const mockTOCItems = [
Expand Down Expand Up @@ -67,18 +66,3 @@ export default meta;
const Template = (args) => <InPageTOC {...args} />;

export const Basic = Template.bind({});

export const Collapsed = Template.bind({});
Collapsed.args = {
collapsed: true,
};

export const Open = Template.bind({});
Open.args = Collapsed.args;
Open.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);

const summary = canvas.getByText('On this page');

await userEvent.click(summary);
};
68 changes: 6 additions & 62 deletions src/components/basics/InPageTOC.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,11 @@
import * as React from 'react';
import { styled } from '@storybook/theming';
import { ChevronSmallDownIcon } from '@storybook/icons';
import { color, fontFamily, spacing, Text } from '@chromaui/tetra';
import { color, spacing, Text } from '@chromaui/tetra';

const Heading = styled((props) => <Text as="h2" variant="heading16" {...props} />)`
margin-bottom: ${spacing[3]};
`;

const Summary = styled.summary`
border: 0;
border-radius: ${spacing[1]};
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0 0.5rem;
margin-left: -0.5rem;
background: transparent;
color: ${color.slate500};
height: 1.75rem;
font-size: 0.75rem;
font-weight: 600;
font-family: ${fontFamily.sans};
gap: 0.375rem;
transition: all 0.16s ease-in-out;
&:hover {
background: rgba(255, 255, 255, 0.1);
}
[open] > & {
margin-bottom: ${spacing[3]};
& > .CaretDown {
transform: rotate(-180deg) translateY(0px);
}
}
`;

const CaretDown = styled.div`
position: relative;
width: 14px;
height: 14px;
transition: transform 250ms ease;
`;

const List = styled.ol`
list-style: none;
margin: 0;
Expand Down Expand Up @@ -77,12 +38,12 @@ type Item = {
};

type InPageTOCProps = {
collapsed?: boolean;
items: Item[];
};

export const InPageTOC = ({ collapsed, items }: InPageTOCProps) => {
const toc = (
export const InPageTOC = ({ items }: InPageTOCProps) => (
<>
<Heading>On this page</Heading>
<List>
{items.map((h2Item) => (
<TOCItem key={h2Item.title}>
Expand All @@ -108,22 +69,5 @@ export const InPageTOC = ({ collapsed, items }: InPageTOCProps) => {
</TOCItem>
))}
</List>
);

return collapsed ? (
<details>
<Summary>
On this page
<CaretDown className="CaretDown">
<ChevronSmallDownIcon aria-hidden />
</CaretDown>
</Summary>
{toc}
</details>
) : (
<>
<Heading>On this page</Heading>
{toc}
</>
);
};
</>
);
4 changes: 2 additions & 2 deletions src/components/screens/DocsScreen/DocsScreen.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { styled } from '@storybook/theming';

import DocsScreen from './DocsScreen';
import DocsScreen, { IS_2_COL_BREAKPOINT } from './DocsScreen';
import compiledMDX from '../../../../.storybook/compiled-mdx';
import { pageContext } from '../../layout/DocsLayout.stories';

Expand Down Expand Up @@ -104,6 +104,6 @@ export const WithTableOfContents = () => (
);
WithTableOfContents.parameters = {
chromatic: {
viewports: [400, 1400],
viewports: [400, IS_2_COL_BREAKPOINT],
},
};
123 changes: 61 additions & 62 deletions src/components/screens/DocsScreen/DocsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,59 +32,59 @@ const { color: dsColor, spacing: dsSpacing, typography } = styles;
const MIN_HEADINGS_COUNT_FOR_TOC = 3;

/**
* TODO: This breakpoint is a compromise:
* - Nav from `components-marketing` and `Container` from `tetra` both apply a bigger margin at
* wider viewports, which results in a too narrow overall available width
* - That worked fine for a 1-col content layout, but does not work for a 2-col layout
* Note: This breakpoint should be revisited.
* - It provides a minimum width of 600px for the content area.
* - The rest of the SB properties (and the prior design of docs) use a 2-col width. To maintain a
* legible line length, the left/right margins of the page layout (codified in Nav from
* `components-marketing` and Container from `tetra`) increase at 1200px. But that doesn't leave
* much available width for a 3-column layout, resulting in this rather wide breakpoint.
* - To reduce this breakpoint (making the InPageTOC visible for more users), we'd need to either:
* a. Change the page layout for _just_ the docs, resulting in a different layout from the other
* SB properties
* b. Change the page layout for all SB properties, resulting in longer line lengths or necessary
* layout adjustments in some places
*/
const IS_2_COL_BREAKPOINT = 1400;
export const IS_2_COL_BREAKPOINT = 1548;

const RIGHT_RAIL_WIDTH = '220px';

// Magic number to account for PageLayout header height
const IN_PAGE_TOC_TOP_OFFSET = 112;
const RIGHT_RAIL_TOP_OFFSET = '112px';

const Root = styled('div', {
shouldForwardProp: (prop) => prop !== 'hasRightRail',
})<{ hasRightRail: boolean }>`
${({ hasRightRail }) =>
hasRightRail &&
css`
@media (min-width: ${IS_2_COL_BREAKPOINT}px) {
display: grid;
grid-template-columns: 1fr 240px;
grid-template-rows: repeat(2, min-content);
grid-column-gap: ${spacing[8]};
}
display: flex;
flex-direction: row-reverse;
gap: ${spacing[8]};
`}
`;

const Header = styled.div`
grid-area: 1 / 1 / 2 / 2;
margin-bottom: ${spacing[8]};
`;

const RightRail = styled.div`
flex: 0 0 ${RIGHT_RAIL_WIDTH};
margin-bottom: ${spacing[8]};
grid-area: 1 / 2 / 3 / 3;
@media (min-width: ${IS_2_COL_BREAKPOINT}px) {
position: relative;
top: -48px;
}
position: relative;
top: -48px;
`;

const RightRailSticky = styled.div`
position: sticky;
top: ${IN_PAGE_TOC_TOP_OFFSET}px;
top: ${RIGHT_RAIL_TOP_OFFSET};
`;

const RightRailRoot = styled(ScrollArea.Root)`
position: relative;
width: 240px;
width: ${RIGHT_RAIL_WIDTH};
margin: 0;
padding-bottom: 0;
padding-right: 20px;
margin-right: 20px;
height: calc(100vh - ${IN_PAGE_TOC_TOP_OFFSET}px);
height: calc(100vh - ${RIGHT_RAIL_TOP_OFFSET});
`;

const RightRailViewport = styled(ScrollArea.Viewport)`
Expand Down Expand Up @@ -118,13 +118,12 @@ const RightRailThumb = styled(ScrollArea.Thumb)`
`;

const Content = styled.div`
grid-area: 2 / 1 / 3 / 2;
flex: 1 1 auto;
min-width: 0;
`;

const MDWrapper = styled.main`
${mdFormatting}
flex: 1;
`;

const Title = styled.h1`
Expand Down Expand Up @@ -215,6 +214,8 @@ function DocsScreen({ data, pageContext, location }) {
const hasHeadings =
pageTocItems.flatMap((item) => (item.items ? [item, ...item.items] : item)).length >
MIN_HEADINGS_COUNT_FOR_TOC;
const [is2Col] = useMediaQuery(`(min-width: ${IS_2_COL_BREAKPOINT}px)`);
const hasRightRail = is2Col && hasHeadings;

const {
allRenderers,
Expand All @@ -232,8 +233,6 @@ function DocsScreen({ data, pageContext, location }) {
renderer: [renderer],
} = useDocsContext();

const [is2Col] = useMediaQuery(`(min-width: ${IS_2_COL_BREAKPOINT}px)`);

const CodeSnippetsWithState = useMemo(() => {
return (props) => (
<CodeSnippets currentFramework={renderer} currentCodeLanguage={codeLanguage} {...props} />
Expand Down Expand Up @@ -316,44 +315,44 @@ function DocsScreen({ data, pageContext, location }) {
return (
<>
<SocialGraph url={`${homepageUrl}${fullPath}/`} title={title} desc={description} />
<Root hasRightRail={hasHeadings}>
<Header>
<Title>{isInstallPage ? `${title} for ${stylizeRenderer(renderer)}` : title}</Title>
<RendererSelector coreRenderers={coreRenderers} communityRenderers={communityRenderers} />
{unsupported && (
<UnsupportedBanner>
This feature is not supported in {stylizeRenderer(renderer)} yet. Help the open source
community by contributing a PR.
{featureSupportItem && (
<>
{' '}
<Link LinkWrapper={GatsbyLinkWrapper} href={featureSupportItem.path} withArrow>
View feature coverage by renderer
</Link>
</>
)}
</UnsupportedBanner>
)}
</Header>
{hasHeadings && (
<Root hasRightRail={hasRightRail}>
{hasRightRail && (
<RightRail>
{is2Col ? (
<RightRailSticky>
<RightRailRoot>
<RightRailViewport>
<InPageTOC items={pageTocItems} />
</RightRailViewport>
<RightRailScrollbar orientation="vertical">
<RightRailThumb />
</RightRailScrollbar>
</RightRailRoot>
</RightRailSticky>
) : (
<InPageTOC collapsed items={pageTocItems} />
)}
<RightRailSticky>
<RightRailRoot>
<RightRailViewport>
<InPageTOC items={pageTocItems} />
</RightRailViewport>
<RightRailScrollbar orientation="vertical">
<RightRailThumb />
</RightRailScrollbar>
</RightRailRoot>
</RightRailSticky>
</RightRail>
)}
<Content>
<Header>
<Title>{isInstallPage ? `${title} for ${stylizeRenderer(renderer)}` : title}</Title>
<RendererSelector
coreRenderers={coreRenderers}
communityRenderers={communityRenderers}
/>
{unsupported && (
<UnsupportedBanner>
This feature is not supported in {stylizeRenderer(renderer)} yet. Help the open
source community by contributing a PR.
{featureSupportItem && (
<>
{' '}
<Link LinkWrapper={GatsbyLinkWrapper} href={featureSupportItem.path} withArrow>
View feature coverage by renderer
</Link>
</>
)}
</UnsupportedBanner>
)}
</Header>

<MDWrapper>
<MDXProvider
components={{
Expand Down

0 comments on commit 5411a51

Please sign in to comment.