Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-implement show/hide buttons on containers #12986

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
8 changes: 0 additions & 8 deletions dotcom-rendering/src/components/FrontPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { Metrics } from './Metrics.importable';
import { ReaderRevenueDev } from './ReaderRevenueDev.importable';
import { SetABTests } from './SetABTests.importable';
import { SetAdTargeting } from './SetAdTargeting.importable';
import { ShowHideContainers } from './ShowHideContainers.importable';
import { SkipTo } from './SkipTo';

type Props = {
Expand Down Expand Up @@ -71,13 +70,6 @@ export const FrontPage = ({ front, NAV }: Props) => {
tests={front.config.abTests}
/>
</Island>
<Island priority="enhancement" defer={{ until: 'idle' }}>
<ShowHideContainers
disableFrontContainerToggleSwitch={
!!front.config.switches.disableFrontContainerShowHide
}
/>
</Island>
<Island priority="critical">
<SetABTests
abTestSwitches={filterABTestSwitches(front.config.switches)}
Expand Down
9 changes: 7 additions & 2 deletions dotcom-rendering/src/components/FrontSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { ContainerTitle } from './ContainerTitle';
import { FrontPagination } from './FrontPagination';
import { FrontSectionTitle } from './FrontSectionTitle';
import { Island } from './Island';
import { ShowHideButton } from './ShowHideButton';
import { ShowHideButton } from './ShowHideButton.importable';
import { ShowMore } from './ShowMore.importable';
import { Treats } from './Treats';

Expand Down Expand Up @@ -579,7 +579,12 @@ export const FrontSection = ({

{isToggleable && (
<div css={sectionShowHide}>
<ShowHideButton sectionId={sectionId} />
<Island
priority="enhancement"
defer={{ until: 'idle' }}
>
<ShowHideButton sectionId={sectionId} />
</Island>
</div>
)}

Expand Down
10 changes: 3 additions & 7 deletions dotcom-rendering/src/components/Island.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { SendTargetingParams } from './SendTargetingParams.importable';
import { SetABTests } from './SetABTests.importable';
import { SetAdTargeting } from './SetAdTargeting.importable';
import { ShareButton } from './ShareButton.importable';
import { ShowHideContainers } from './ShowHideContainers.importable';
import { ShowHideButton } from './ShowHideButton.importable';
import { SignInGateSelector } from './SignInGateSelector.importable';
import { SlotBodyEnd } from './SlotBodyEnd.importable';
import { StickyBottomBanner } from './StickyBottomBanner.importable';
Expand Down Expand Up @@ -364,13 +364,9 @@ describe('Island: server-side rendering', () => {
).not.toThrow();
});

test('ShowHideContainers', () => {
test('ShowHideButton', () => {
expect(() =>
renderToString(
<ShowHideContainers
disableFrontContainerToggleSwitch={false}
/>,
),
renderToString(<ShowHideButton sectionId="opinion" />),
).not.toThrow();
});

Expand Down
10 changes: 8 additions & 2 deletions dotcom-rendering/src/components/Section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import { ContainerTitle } from './ContainerTitle';
import { ElementContainer } from './ElementContainer';
import { Flex } from './Flex';
import { Hide } from './Hide';
import { Island } from './Island';
import { LeftColumn } from './LeftColumn';
import { ShowHideButton } from './ShowHideButton';
import { ShowHideButton } from './ShowHideButton.importable';
import { Treats } from './Treats';

/**
Expand Down Expand Up @@ -364,7 +365,12 @@ export const Section = ({
/>
</MaybeHideAboveLeftCol>
{toggleable && !!sectionId && (
<ShowHideButton sectionId={sectionId} />
<Island
priority="enhancement"
defer={{ until: 'idle' }}
>
<ShowHideButton sectionId={sectionId} />
</Island>
)}
</div>
{toggleable && sectionId ? (
Expand Down
96 changes: 96 additions & 0 deletions dotcom-rendering/src/components/ShowHideButton.importable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { css } from '@emotion/react';
import { isObject, isString, storage } from '@guardian/libs';
import { space, textSans14 } from '@guardian/source/foundations';
import { Button } from '@guardian/source/react-components';
import { useEffect, useState } from 'react';
import { useIsSignedIn } from '../lib/useAuthStatus';
import { palette } from '../palette';

type Props = {
sectionId: string;
};

const showHideButtonCss = css`
button {
${textSans14};
margin-right: 10px;
margin-bottom: ${space[2]}px;
position: relative;
align-items: bottom;
text-decoration: none;
}
`;

type ContainerStates = { [id: string]: string };

const isContainerStates = (item: unknown): item is ContainerStates => {
if (!isObject(item)) return false;
if (!Object.keys(item).every(isString)) return false;
if (!Object.values(item).every(isString)) return false;
return true;
};

const getContainerStates = (): ContainerStates => {
const item = storage.local.get(`gu.prefs.container-states`);
if (!isContainerStates(item)) return {};
return item;
};

/**
* Component to toggle the visibility of a front container. Used within FrontSection.
**/
export const ShowHideButton = ({ sectionId }: Props) => {
const [containerStates, setContainerStates] = useState<ContainerStates>({});
const [isExpanded, setIsExpanded] = useState(true);
const textShowHide = isExpanded ? 'Hide' : 'Show';
const isSignedIn = useIsSignedIn();

const toggleContainer = () => {
const section: Element | null =
window.document.getElementById(sectionId);

if (isExpanded) {
containerStates[sectionId] = 'closed';
section?.classList.add('hidden');
} else {
containerStates[sectionId] = 'opened';
section?.classList.remove('hidden');
}

storage.local.set(`gu.prefs.container-states`, containerStates);
};

useEffect(() => {
const section: Element | null =
window.document.getElementById(sectionId);

setContainerStates(getContainerStates());

const isClosed = containerStates[sectionId] === 'closed';
setIsExpanded(!isClosed);

isClosed
? section?.classList.add('hidden')
: section?.classList.remove('hidden');
}, [containerStates, sectionId]);

return (
isSignedIn === true && (
<div css={showHideButtonCss}>
<Button
priority="subdued"
data-link-name={textShowHide}
data-show-hide-button={sectionId}
aria-controls={sectionId}
aria-expanded={isExpanded}
theme={{
textSubdued: palette('--section-toggle-button'),
}}
onClick={toggleContainer}
>
{textShowHide}
</Button>
</div>
)
);
};
14 changes: 14 additions & 0 deletions dotcom-rendering/src/components/ShowHideButton.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { Meta } from '@storybook/react';
import { ShowHideButton } from './ShowHideButton.importable';

const meta = {
title: 'Components/ShowHideButton',
component: ShowHideButton,
args: {
sectionId: 'sectionId',
},
} satisfies Meta<typeof ShowHideButton>;

export default meta;

export const Default = {};
42 changes: 0 additions & 42 deletions dotcom-rendering/src/components/ShowHideButton.tsx

This file was deleted.

This file was deleted.

Loading