Skip to content

Commit

Permalink
Add support for category page sidebars
Browse files Browse the repository at this point in the history
  • Loading branch information
woodwoerk committed Sep 26, 2023
1 parent b887192 commit d105779
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 53 deletions.
16 changes: 14 additions & 2 deletions common/__generated__/graphql.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

135 changes: 135 additions & 0 deletions components/categories/CategoryPageContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import React from 'react';
import { Container, Row } from 'reactstrap';
import styled, { css } from 'styled-components';

import StreamField from 'components/common/StreamField';
import { GetPlanPageGeneralQuery } from 'common/__generated__/graphql';
import CategoryPageStreamField, {
checkAttributeHasValueByType,
} from 'components/common/CategoryPageStreamField';

type GeneralPlanPage = NonNullable<GetPlanPageGeneralQuery['planPage']>;

type CategoryPage = { __typename: 'CategoryPage' } & GeneralPlanPage;

const MainContent = styled.div``;

const AsideContent = styled.div`
position: sticky;
top: ${({ theme }) => theme.spaces.s200};
flex: 0 1 300px;
width: 300px;
background-color: ${({ theme }) => theme.themeColors.white};
border-radius: ${({ theme }) => theme.cardBorderRadius};
padding: ${({ theme }) => theme.spaces.s100} 0;
display: flex;
flex-direction: column;
align-items: stretch;
`;

const columnLayout = css`
display: flex;
justify-content: center;
align-items: flex-start;
padding: ${({ theme }) => `0 ${theme.spaces.s200} ${theme.spaces.s200}`};
gap: ${({ theme }) => theme.spaces.s300};
${MainContent} {
flex: 0 2 800px;
padding: 0 ${({ theme }) => theme.spaces.s100};
background-color: ${({ theme }) => theme.themeColors.white};
border-radius: ${({ theme }) => theme.cardBorderRadius};
}
@media (max-width: ${({ theme }) => theme.breakpointLg}) {
flex-direction: column-reverse;
justify-content: flex-start;
align-items: stretch;
${MainContent}, ${AsideContent} {
position: relative;
top: 0;
flex: 1 0 auto;
width: 100%;
max-width: ${({ theme }) => theme.breakpointMd};
margin: 0 auto;
}
}
@media (max-width: ${({ theme }) => theme.breakpointMd}) {
gap: ${({ theme }) => theme.spaces.s150};
}
@media (max-width: ${({ theme }) => theme.breakpointSm}) {
padding: ${({ theme }) => `0 ${theme.spaces.s050} ${theme.spaces.s050}`};
}
`;

const ContentArea = styled.div<{
$columnLayout: boolean;
$backgroundColor?: string;
}>`
${({ $columnLayout }) => $columnLayout && columnLayout};
background-color: ${({ $backgroundColor }) => $backgroundColor};
`;

const CategoryPageContent = ({
page,
pageSectionColor,
}: {
page: CategoryPage;
pageSectionColor: string;
}) => {
const hasMainContentTemplate = !!page.layout?.layoutMainBottom;
const hasAsideTemplate = !!page.layout?.layoutAside;
const hasAside =
hasAsideTemplate &&
page.layout?.layoutAside?.some((block) =>
checkAttributeHasValueByType(block.attributeType.identifier, page)
);

return (
<ContentArea
$columnLayout={hasAside}
$backgroundColor={hasAside ? pageSectionColor : undefined}
>
<MainContent>
{hasMainContentTemplate
? page.layout?.layoutMainBottom?.map((block, i) => (
<CategoryPageStreamField
key={i}
page={page}
block={block}
hasAsideColumn={hasAside}
/>
))
: page.body && (
<StreamField
page={page}
blocks={page.body}
color={pageSectionColor}
/>
)}
</MainContent>

{hasAside && (
<AsideContent>
<Container>
{page.layout?.layoutAside?.map((block, i) => (
<Row key={i}>
<CategoryPageStreamField
page={page}
block={block}
context="aside"
columnProps={{ md: 12 }}
/>
</Row>
))}
</Container>
</AsideContent>
)}
</ContentArea>
);
};

export default CategoryPageContent;
59 changes: 49 additions & 10 deletions components/common/CategoryPageStreamField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ type OmitFields<T> = OmitUnion<

interface WrapperProps {
children: React.ReactNode;
withContainer: boolean;
withContainer?: boolean;
}

const Wrapper = ({ children, withContainer }: WrapperProps) =>
const Wrapper = ({ children, withContainer = true }: WrapperProps) =>
withContainer ? (
<Container>
<Row>{children}</Row>
Expand All @@ -46,34 +46,65 @@ const DEFAULT_COL_PROPS = {
className: 'my-4',
};

const TIGHT_COL_PROPS = {
xl: { size: 8, offset: 2 },
lg: { size: 10, offset: 1 },
md: { size: 12 },
className: 'my-4',
};

interface Props {
page: CategoryPage;
context?: 'hero' | 'main' | 'aside';
/** Passed down to reactstrap Col components */
columnProps?: any;
hasAsideColumn?: boolean;
block:
| OmitFields<CategoryPageMainTopBlock>
| OmitFields<CategoryPageMainBottomBlock>;
}

const findAttributeByType = (attributeTypeIdentifier: string, page) =>
page.category?.attributes?.find(
(attribute) => attribute.type.identifier === attributeTypeIdentifier
);

export const checkAttributeHasValueByType = (
attributeTypeIdentifier: string,
page
) => {
const attribute = findAttributeByType(attributeTypeIdentifier, page);

return attribute && attributeHasValue(attribute);
};

export const CategoryPageStreamField = ({
block,
page,
context = 'main',
columnProps: customColumnProps,
hasAsideColumn = false,
}: Props) => {
const theme = useTheme();
const plan = usePlan();
const columnProps =
context === 'main' && hasAsideColumn ? TIGHT_COL_PROPS : DEFAULT_COL_PROPS;

switch (block.__typename) {
case 'CategoryPageAttributeTypeBlock': {
const withContainer = context === 'main';
const attribute = page.category?.attributes?.find(
(attribute) =>
attribute.type.identifier === block.attributeType.identifier
const attribute = findAttributeByType(
block.attributeType.identifier,
page
);

if (attribute && attributeHasValue(attribute)) {
return (
<Wrapper withContainer={withContainer}>
<Col {...(withContainer ? DEFAULT_COL_PROPS : { md: 6 })}>
<Col
{...(withContainer ? columnProps : { md: 6 })}
{...customColumnProps}
>
<ActionAttribute
attribute={attribute}
attributeType={undefined}
Expand All @@ -88,8 +119,8 @@ export const CategoryPageStreamField = ({

case 'CategoryPageContactFormBlock': {
return (
<Wrapper withContainer>
<Col {...DEFAULT_COL_PROPS}>
<Wrapper>
<Col {...columnProps} {...customColumnProps}>
<ExpandableFeedbackFormBlock
heading={block.heading || undefined}
description={block.description || undefined}
Expand All @@ -106,7 +137,7 @@ export const CategoryPageStreamField = ({

return (
<Wrapper withContainer={context === 'main'}>
<Col xs={12}>
<Col xs={12} {...customColumnProps}>
<CategoryMetaBar category={page.category.id} />
</Col>
</Wrapper>
Expand All @@ -119,7 +150,15 @@ export const CategoryPageStreamField = ({
page.category?.parent?.color ||
theme.brandLight;

return <StreamField page={page} blocks={page.body} color={color} />;
return (
<StreamField
page={page}
blocks={page.body}
color={color}
hasSidebar={hasAsideColumn}
columnProps={columnProps}
/>
);
}

case 'CategoryPageCategoryListBlock': {
Expand Down
11 changes: 8 additions & 3 deletions components/common/StreamField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,11 @@ type StreamFieldBlockProps = {
block: StreamFieldFragmentFragment;
color: string;
hasSidebar: boolean;
columnProps?: any;
};

function StreamFieldBlock(props: StreamFieldBlockProps) {
const { id, page, block, color, hasSidebar } = props;
const { id, page, block, color, hasSidebar, columnProps } = props;
const { __typename } = block;
const plan = useContext(PlanContext);
const theme = useTheme();
Expand All @@ -304,6 +305,7 @@ function StreamFieldBlock(props: StreamFieldBlockProps) {
lg={{ size: 8, offset: hasSidebar ? 4 : 2 }}
md={{ size: 10, offset: 1 }}
className="my-4"
{...columnProps}
>
<RichText html={value} isCollapsible={isCollapsible} />
</Col>
Expand Down Expand Up @@ -332,7 +334,7 @@ function StreamFieldBlock(props: StreamFieldBlockProps) {
return (
<Container id={id}>
<Row>
<Col>
<Col {...columnProps}>
<div>{value}</div>
</Col>
</Row>
Expand Down Expand Up @@ -456,6 +458,7 @@ function StreamFieldBlock(props: StreamFieldBlockProps) {
lg={{ size: 8, offset: hasSidebar ? 4 : 2 }}
md={{ size: 10, offset: 1 }}
className="my-4"
{...columnProps}
>
<div dangerouslySetInnerHTML={{ __html: block.embed.html }}></div>
</Col>
Expand Down Expand Up @@ -506,10 +509,11 @@ interface StreamFieldProps {
page: any;
blocks: any;
hasSidebar?: boolean;
columnProps?: any;
}

function StreamField(props: StreamFieldProps) {
const { page, blocks, color, hasSidebar = false } = props;
const { page, blocks, color, hasSidebar = false, columnProps } = props;

return (
<>
Expand All @@ -521,6 +525,7 @@ function StreamField(props: StreamFieldProps) {
key={block.id}
color={color}
hasSidebar={hasSidebar}
columnProps={columnProps}
/>
))}
</>
Expand Down
Loading

0 comments on commit d105779

Please sign in to comment.