Skip to content

Commit

Permalink
Merge pull request #9716 from CitizenLabDotCo/TAN-3233/sticky-nav-pos…
Browse files Browse the repository at this point in the history
…itioning-with-context

Tan 3233/sticky nav positioning
  • Loading branch information
brentguf authored Dec 12, 2024
2 parents a283096 + 0c775f2 commit 49e5ace
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 94 deletions.
1 change: 0 additions & 1 deletion front/.storybook/contexts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ const Portals = () => (
id="modal-portal"
style={{ position: 'absolute', top: 0, left: 0, width: '100%' }}
/>
<div id="topbar-portal" />
<div id="mobile-nav-portal" />
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React from 'react';

import { Title } from '@citizenlab/cl2-component-library';
import styled from 'styled-components';
Expand Down Expand Up @@ -58,27 +58,17 @@ const ContentRight = ({
onChangeTopics,
onChangeSort,
}: Props) => {
const [isCTABarVisible, setIsCTABarVisible] = useState(false);

useEffect(() => {
function checkCTABarVisibility() {
if (document.getElementById('project-cta-bar')) {
setIsCTABarVisible(true);
return;
}

setIsCTABarVisible(false);
}

window.addEventListener('scrollend', checkCTABarVisibility);
return () => window.removeEventListener('scrollend', checkCTABarVisibility);
}, []);
/*
Likely not the most reliable way to determine if the bar is present.
Context would probably be better, but this is a quick fix.
*/
const projectCTABarTop = document.getElementById('project-cta-bar-top');

return (
<Container
id="e2e-ideas-filters"
top={isCTABarVisible ? 160 : 100}
maxHeightOffset={isCTABarVisible ? 180 : 120}
top={projectCTABarTop ? 160 : 100}
maxHeightOffset={projectCTABarTop ? 180 : 120}
gapWidth={gapWidth}
>
{/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ const ParticipationCTAContent = ({
}: Props) => {
const theme = useTheme();
const isSmallerThanPhone = useBreakpoint('phone');
// This is the same condition we have in ProjectCTABar.
const sticksToBottom = isSmallerThanPhone;

return isSmallerThanPhone ? (
return sticksToBottom ? (
<Box
display="flex"
flexDirection="column"
Expand Down Expand Up @@ -54,6 +56,19 @@ const ParticipationCTAContent = ({
bgColor={theme.colors.tenantPrimary}
height="64px"
p="20px"
/*
This is is needed to determine how much to push down the input filters
(in ContentRight).
Putting this id in ProjectCTABar does not work at the moment, because
the rendered bar (BarContents) can sometimes be null. In that case,
we are telling ContentRight that the top bar is visible, while it is not.
We can look into moving this component to ProjectCTABar (where we split between top and bottom bar)
instead of here. Then only define the CTAButton part in the config, then we can probably
move the id in ProjectCTABar.
*/
id="project-cta-bar-top"
>
<Box display="flex" width="100%" maxWidth={`${maxPageWidth}px`}>
<TimeIndicator
Expand Down
3 changes: 0 additions & 3 deletions front/app/containers/App/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -333,9 +333,6 @@ const App = ({ children }: Props) => {
<ErrorBoundary>
<div id="modal-portal" />
</ErrorBoundary>
<ErrorBoundary>
<div id="topbar-portal" />
</ErrorBoundary>
<ErrorBoundary>
<Suspense fallback={null}>
<ConsentManager />
Expand Down
6 changes: 5 additions & 1 deletion front/app/containers/PlatformFooter/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,11 @@ const PlatformFooter = ({ className }: Props) => {
eventEmitter.emit('openConsentManager');
};

const participationBar = document.getElementById('project-cta-bar');
/*
Likely not the most reliable way to determine if the bar is present.
Context would probably be better, but this is a quick fix.
*/
const participationBar = document.getElementById('project-cta-bar-bottom');

useEffect(() => {
setPaddingBottom(
Expand Down
92 changes: 26 additions & 66 deletions front/app/containers/ProjectsShowPage/ProjectCTABar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import React, { useEffect, useState } from 'react';
import React from 'react';

import {
Box,
BoxProps,
colors,
stylingConsts,
useBreakpoint,
} from '@citizenlab/cl2-component-library';
import { createPortal } from 'react-dom';

import usePhases from 'api/phases/usePhases';
import useProjectById from 'api/projects/useProjectById';

import MainHeader from 'containers/MainHeader';

import {
getMethodConfig,
getParticipationMethod,
Expand All @@ -24,39 +22,10 @@ type ProjectCTABarProps = {

const ProjectCTABar = ({ projectId }: ProjectCTABarProps) => {
const isSmallerThanTablet = useBreakpoint('tablet');
const isSmallerThanPhone = useBreakpoint('phone');
// On devices larger than phones, the sticky CTA bar is only visible when the action button is out of view
const [sticksToTop, setSticksToTop] = useState(false);
// The CTA bar is always visible on phones
const sticksToBottom = isSmallerThanPhone;
const portalElement = document.getElementById('topbar-portal');
const sticksToBottom = isSmallerThanTablet;
const { data: phases } = usePhases(projectId);
const { data: project } = useProjectById(projectId);

useEffect(() => {
const handleScroll = () => {
const actionButtonElement = document.getElementById(
'participation-detail'
);
const actionButtonYOffset = actionButtonElement
? actionButtonElement.getBoundingClientRect().top + window.scrollY
: undefined;

setSticksToTop(
!!(
!sticksToBottom &&
actionButtonElement &&
actionButtonYOffset &&
window.scrollY > actionButtonYOffset - (isSmallerThanTablet ? 14 : 30)
)
);
};

window.addEventListener('scroll', handleScroll, { passive: true });

return () => window.removeEventListener('scroll', handleScroll);
}, [isSmallerThanTablet, sticksToBottom]);

const participationMethod = project
? getParticipationMethod(project.data, phases?.data)
: undefined;
Expand All @@ -65,42 +34,33 @@ const ProjectCTABar = ({ projectId }: ProjectCTABarProps) => {
return null;
}

// WARNING: BarContents types are wrong. Can also be null.
const BarContents = getMethodConfig(participationMethod).renderCTABar({
project: project.data,
phases: phases?.data,
});

if ((sticksToBottom || sticksToTop) && portalElement) {
const sharedProps: BoxProps = {
width: '100vw',
position: 'fixed',
zIndex: '1000',
background: colors.white,
id: 'project-cta-bar',
};
let portalContent: JSX.Element | null = null;

if (sticksToBottom) {
portalContent = (
<Box bottom="0px" {...sharedProps}>
{BarContents}
</Box>
);
} else if (sticksToTop) {
portalContent = (
<Box top="0px" {...sharedProps}>
<Box height="78px">
<MainHeader />
</Box>
{BarContents}
</Box>
);
}

return createPortal(portalContent, portalElement);
}

return <>{BarContents}</>;
const sharedProps: BoxProps = {
width: '100vw',
zIndex: '1000',
background: colors.white,
};
const otherProps: BoxProps = sticksToBottom
? {
// This id is needed to add padding to PlatformFooter
id: 'project-cta-bar-bottom',
position: 'fixed',
bottom: '0px',
}
: {
position: 'sticky',
top: `${stylingConsts.menuHeight}px`,
};

return (
<Box {...sharedProps} {...otherProps}>
{BarContents}
</Box>
);
};

export default ProjectCTABar;
5 changes: 1 addition & 4 deletions front/app/containers/ProjectsShowPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ interface Props {

const ProjectsShowPage = ({ project }: Props) => {
const projectId = project.id;

const isSmallerThanTablet = useBreakpoint('tablet');
const { formatMessage } = useIntl();
const [mounted, setMounted] = useState(false);
Expand Down Expand Up @@ -134,9 +133,7 @@ const ProjectsShowPage = ({ project }: Props) => {
<ProjectHeader projectId={projectId} />
<ProjectCTABar projectId={projectId} />

<div id="participation-detail">
<TimelineContainer projectId={projectId} />
</div>
<TimelineContainer projectId={projectId} />
{!!events?.data.length && (
<Box
id="e2e-events-section-project-page"
Expand Down

0 comments on commit 49e5ace

Please sign in to comment.