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

Reuse one component for sticky headings #926

Merged
merged 6 commits into from
Apr 15, 2024
Merged
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
5 changes: 5 additions & 0 deletions components/NavBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,14 @@ export const NavBar = ({ color }) => {

const logoutUser = (e) => {
e.preventDefault()
setShowMenu(false)
logout()
}

useEffect(() => {
setShowMenu(false)
}, [pathname])

return (
<StyledNavBar $bgColor={color}>
<Container>
Expand Down
21 changes: 18 additions & 3 deletions components/SharedStyledComponents.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Box, Button, Container, Flex, Heading } from 'ooni-components'
import styled from 'styled-components'
import { Button } from 'ooni-components'

export const StyledSticky = styled.div`
position: sticky;
Expand All @@ -15,14 +15,29 @@ top: 0;
z-index: 100;
`

export const StyledStickySubMenu = styled.div`
export const StyledStickySubMenu = styled(Box)`
position: sticky;
top: 66px;
top: 65.5px;
background: white;
z-index: 99;
border-bottom: 1px solid ${props => props.theme.colors.gray3};
`

export const StickySubMenu = ({ title, children }) => {
return (
<StyledStickySubMenu mt={[0, 4]} mb={2} pb={[2, 0]}>
<Flex justifyContent='space-between' alignItems={['flex-start', 'center']} flexDirection={['column', 'column', 'row']}>
<Heading h={1} mt={1} mb={0} fontSize={[4, 5]}>
{title}
</Heading>
<Box>
{children}
</Box>
</Flex>
</StyledStickySubMenu>
)
}

// port the design to ooni-components
export const StyledHollowButton = styled(Button)`
&:hover {
Expand Down
4 changes: 2 additions & 2 deletions cypress/e2e/countries.e2e.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ describe('Countries Page Tests', () => {
})

it('first region (Africa) is visible', () => {
cy.get(':nth-child(1) > h1')
cy.get('h2')
.contains('Africa')
.should('be.visible')
})

it('clicking on region in menu scrolls down to the correct region', () => {
cy.get('a[href="#Europe"]').click({ force: true })
cy.get(':nth-child(4) > h1')
cy.get('h2')
.contains('Europe')
.should('be.visible')
})
Expand Down
50 changes: 19 additions & 31 deletions pages/countries.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,24 @@ import { FormattedMessage, useIntl } from 'react-intl'
import styled from 'styled-components'

import CountryList from 'components/CountryBox'
import { StyledStickySubMenu } from 'components/SharedStyledComponents'
import countryUtil from 'country-util'
import { getLocalisedRegionName } from 'utils/i18nCountries'
import { StickySubMenu } from '../components/SharedStyledComponents'

// To compenstate for the sticky navigation bar
// :target selector applies only the element with id that matches
// the current URL fragment (e.g '/#Africa')
const RegionHeaderAnchor = styled.div`
:target::before {
content: ' ';
display: block;
width: 0;
/* Height of the combined header (NavBar and Regions) */
/* This is needed to compensate the for the sticky navbar and region
links bar when scrolling to the selected region. And the height of these
bars changes in the mobile layout. This has evolved to be a bad design
that needs to be replaced. */
height: 145px;
margin-top: -145px;
@media(max-width: 768px) {
height: 375px;
margin-top: -375px;
}
/* Height of the combined header (NavBar and Regions) */
/* This is needed to compensate the for the sticky navbar and region
links bar when scrolling to the selected region. And the height of these
bars changes in the mobile layout. This has evolved to be a bad design
that needs to be replaced. */
height: 140px;
margin-top: -140px;
@media(max-width: 768px) {
height: 200px;
margin-top: -200px;
}
`

Expand Down Expand Up @@ -67,7 +62,7 @@ const RegionBlock = ({regionCode, countries}) => {
return (
<Box my={3}>
<RegionHeaderAnchor id={regionName} />
<Heading h={1} center py={2}>{regionName}</Heading>
<Heading h={2} py={2}>{regionName}</Heading>
<CountryList
countries={countries}
itemsPerRow={4}
Expand All @@ -79,18 +74,13 @@ const RegionBlock = ({regionCode, countries}) => {
const StyledRegionLink = styled.a`
display: block;
color: ${(props) => props.theme.colors.blue5};
text-decoration: none;
border-bottom: 2px solid transparent;
:hover {
border-bottom: 2px solid ${(props) => props.theme.colors.blue5};
width: 100%;
}
text-decoration: underline;
`

const RegionLink = ({ href, label }) => (
<Box px={[2,3]} py={[2,2,4]}>
<Box px={[2,3]}>
<StyledRegionLink href={href}>
<Text fontSize={[16, 20]}>{label}</Text>
<Text fontSize={1}>{label}</Text>
</StyledRegionLink>
</Box>
)
Expand Down Expand Up @@ -153,8 +143,8 @@ const Countries = ({ countries }) => {
<Head>
<title>{intl.formatMessage({id: 'Countries.PageTitle'})}</title>
</Head>
<StyledStickySubMenu>
<Container>
<Container>
<StickySubMenu title="Countries">
<Flex
flexDirection={['column', 'column', 'row']}
justifyContent={['flex-start', 'flex-end']}
Expand All @@ -179,10 +169,8 @@ const Countries = ({ countries }) => {
<RegionLink href={`#${getLocalisedRegionName('AQ', intl.locale)}`} label={getLocalisedRegionName('AQ', intl.locale)} />
</Flex>
</Flex>
</Container>
</StyledStickySubMenu>

<Container>
</StickySubMenu>

{
// Show a message when there are no countries to show, when search is empty
(filteredCountries.length === 0)
Expand Down
81 changes: 40 additions & 41 deletions pages/domains.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { CategoryBadge } from 'components/Badge'
import GridLoader from 'components/GridLoader'
import { StyledStickySubMenu } from 'components/SharedStyledComponents'
import { StickySubMenu } from 'components/SharedStyledComponents'
import { getCategoryCodesMap } from 'components/utils/categoryCodes'
import useFilterWithSort from 'hooks/useFilterWithSort'
import Head from 'next/head'
import { Box, Container, Flex, Heading, Input, Select, Text } from 'ooni-components'
import { Box, Container, Flex, Input, Select, Text } from 'ooni-components'
import { useMemo } from 'react'
import { useIntl } from 'react-intl'
import { simpleFetcher } from 'services/fetchers'
Expand Down Expand Up @@ -92,48 +92,47 @@ const Domains = () => {
<title>{intl.formatMessage({id: 'General.OoniExplorer'})} | {intl.formatMessage({id: 'Domains.Title'})}</title>
</Head>
<Container>
<StyledStickySubMenu>
<Flex mt={[0, 5]} mb={2} justifyContent='space-between' alignItems='baseline' flexDirection={['column', 'column', 'row']}>
<Heading h={1} mt={1} mb={0} fontSize={[4, 5]}>
{
intl.formatMessage({id: 'Domains.Title'})
} {!!sortedAndFilteredData.length &&
<StickySubMenu
title={
<>
{ intl.formatMessage({id: 'Domains.Title'})}{' '}{!!sortedAndFilteredData.length &&
<>({new Intl.NumberFormat().format(sortedAndFilteredData.length)})</>
}
</Heading>
<Flex sx={{gap: 3}} flexDirection={['column', 'column', 'row']} width={[1, 'auto']}>
<Box>
<Input
onChange={(e) => debouncedSearchHandler(e.target.value)}
placeholder={intl.formatMessage({id: 'Domains.SearchPlaceholder'})}
error={
(searchValue && sortedAndFilteredData?.length === 0) &&
<>{intl.formatMessage({id: 'Domains.SearchError'})}</>
}
/>
</Box>
<Box>
<Select onChange={e => setCategoryValue(e.target.value)}>
<option value=''>{intl.formatMessage({id: 'Domains.AllCategories'})}</option>
{
categoryCodes.map((key) => (
<option key={key} value={key}>
{intl.formatMessage({id: `CategoryCode.${key}.Name`})}
</option>
))
}
</Select>
</Box>
<Box>
<Select value={sortValue} onChange={e => setSortValue(e.target.value)}>
{sortOptions.map(({key, intlKey}) => (
<option key={key} value={key}>{intl.formatMessage({id: intlKey})}</option>
))}
</Select>
</Box>
</Flex>
</>
}
>
<Flex sx={{gap: 3}} flexDirection={['column', 'column', 'row']} width={[1, 'auto']}>
<Box>
<Input
onChange={(e) => debouncedSearchHandler(e.target.value)}
placeholder={intl.formatMessage({id: 'Domains.SearchPlaceholder'})}
error={
(searchValue && sortedAndFilteredData?.length === 0) &&
<>{intl.formatMessage({id: 'Domains.SearchError'})}</>
}
/>
</Box>
<Box>
<Select onChange={e => setCategoryValue(e.target.value)}>
<option value=''>{intl.formatMessage({id: 'Domains.AllCategories'})}</option>
{
categoryCodes.map((key) => (
<option key={key} value={key}>
{intl.formatMessage({id: `CategoryCode.${key}.Name`})}
</option>
))
}
</Select>
</Box>
<Box>
<Select value={sortValue} onChange={e => setSortValue(e.target.value)}>
{sortOptions.map(({key, intlKey}) => (
<option key={key} value={key}>{intl.formatMessage({id: intlKey})}</option>
))}
</Select>
</Box>
</Flex>
</StyledStickySubMenu>
</StickySubMenu>
<Box mt={4}>
{!!displayData.length ?
<Box mt={4}><VirtualizedGrid data={sortedAndFilteredData} /></Box>:
Expand Down
49 changes: 23 additions & 26 deletions pages/findings/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { StyledStickySubMenu } from 'components/SharedStyledComponents'
import { StickySubMenu } from 'components/SharedStyledComponents'
import HighlightBox from 'components/landing/HighlightBox'
import SpinLoader from 'components/vendor/SpinLoader'
import useFilterWithSort from 'hooks/useFilterWithSort'
Expand Down Expand Up @@ -93,32 +93,29 @@ const Index = () => {
{user?.role === 'admin' && (
<Flex justifyContent="end" mt={3}><NLink href="/findings/dashboard"><Button hollow>{intl.formatMessage({id: 'Findings.Dashboard.ShortTitle'})}</Button></NLink></Flex>
)}
<StyledStickySubMenu>
<Flex mt={user?.role === 'admin' ? 0 : [0, 5]} mb={2} justifyContent='space-between' alignItems='baseline' flexDirection={['column', 'column', 'row']}>
<Heading h={1} mt={1} mb={0} fontSize={[4, 5]}>
{intl.formatMessage({id: 'Findings.Index.Title'}, {amount: sortedAndFilteredData.length})}
</Heading>
<Flex sx={{gap: 3}} flexDirection={['column', 'column', 'row']} width={[1, 'auto']}>
<Box>
<Input
onChange={(e) => debouncedSearchHandler(e.target.value)}
placeholder={intl.formatMessage({id: 'Findings.Index.SearchPlaceholder'})}
error={
(searchValue && sortedAndFilteredData?.length === 0) &&
<>{intl.formatMessage({id: 'Findings.Index.SearchError'})}</>
}
/>
</Box>
<Box>
<Select value={sortValue} onChange={e => setSortValue(e.target.value)}>
{sortOptions.map(({key, intlKey}) => (
<option key={key} value={key}>{intl.formatMessage({id: intlKey})}</option>
))}
</Select>
</Box>
</Flex>
<StickySubMenu
title={<>{intl.formatMessage({id: 'Findings.Index.Title'}, {amount: sortedAndFilteredData.length})}</>}
>
<Flex sx={{gap: 3}} flexDirection={['column', 'column', 'row']} width={[1, 'auto']}>
<Box>
<Input
onChange={(e) => debouncedSearchHandler(e.target.value)}
placeholder={intl.formatMessage({id: 'Findings.Index.SearchPlaceholder'})}
error={
(searchValue && sortedAndFilteredData?.length === 0) &&
<>{intl.formatMessage({id: 'Findings.Index.SearchError'})}</>
}
/>
</Box>
<Box>
<Select value={sortValue} onChange={e => setSortValue(e.target.value)}>
{sortOptions.map(({key, intlKey}) => (
<option key={key} value={key}>{intl.formatMessage({id: intlKey})}</option>
))}
</Select>
</Box>
</Flex>
</StyledStickySubMenu>
</StickySubMenu>
{isLoading &&
<Container pt={6}><SpinLoader /></Container>
}
Expand Down
6 changes: 3 additions & 3 deletions pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const StyledStatsItem = styled(Box)`

const StatsItem = ({label, unit, value }) => (
<StyledStatsItem color='blue9' width={[1/3]} p={3}>
<Text fontSize={[42, 48]} fontWeight={300}>
<Text fontSize={[4, 48]} fontWeight={300}>
{value}
<Text as='span' fontSize={32}>{unit}</Text>
</Text>
Expand Down Expand Up @@ -154,7 +154,7 @@ const LandingPage = ({ measurementCount, asnCount, countryCount}) => {
<title>{intl.formatMessage({id: 'General.OoniExplorer'})}</title>
</Head>
<HeroUnit>
<StyledContainer py={[0, 120]} my={[0, 90]}>
<StyledContainer py={[0, 120]} my={[0, 90]} pt={[5, 0]}>
<Text textAlign='center'>
<Heading h={1}>
<Text fontSize={[32, 64]} color='#ffffff'><FormattedMessage id='Home.Banner.Title.UncoverEvidence' /></Text>
Expand All @@ -169,7 +169,7 @@ const LandingPage = ({ measurementCount, asnCount, countryCount}) => {
</StyledContainer>
</HeroUnit>
<Container>
<StatsContainer px={[0, 32]} py={16} mx={[0, '25%']} mt={[0, -120]} mb={48} flexWrap='wrap'>
<StatsContainer px={[0, 32]} py={16} mx={[0, '25%']} mt={[0, -120]} mb={[0, 48]} flexWrap='wrap'>
<StatsItem
label={<FormattedMessage id='Home.Banner.Stats.Measurements' />}
unit={measurementCount.unit}
Expand Down
Loading
Loading