+
+
+
- {navbarSticky ?
+ {navbarSticky ? (
- :
+
+ ) : (
- }
-
- { children }
-
+ )}
+
+ {children}
+
+
+
-
-
+
+
)
}
Layout.propTypes = {
- children: PropTypes.object.isRequired
+ children: PropTypes.object.isRequired,
}
export default Layout
diff --git a/components/MATChart.js b/components/MATChart.js
index e2e25269d..1482c5af7 100644
--- a/components/MATChart.js
+++ b/components/MATChart.js
@@ -1,15 +1,14 @@
-import { Box, Text } from 'ooni-components'
-import { StackedBarChart } from 'components/aggregation/mat/StackedBarChart'
+import axios from 'axios'
import { FunnelChart } from 'components/aggregation/mat/FunnelChart'
+import { MATContextProvider } from 'components/aggregation/mat/MATContext'
import { NoCharts } from 'components/aggregation/mat/NoCharts'
+import { StackedBarChart } from 'components/aggregation/mat/StackedBarChart'
import TableView from 'components/aggregation/mat/TableView'
-import { useMemo } from 'react'
-import useSWR from 'swr'
-import dayjs from 'services/dayjs'
import { axiosResponseTime } from 'components/axios-plugins'
-import axios from 'axios'
-import { MATContextProvider } from 'components/aggregation/mat/MATContext'
+import { useMemo } from 'react'
import { useIntl } from 'react-intl'
+import dayjs from 'services/dayjs'
+import useSWR from 'swr'
import { FormattedMarkdownBase } from './FormattedMarkdown'
axiosResponseTime(axios)
@@ -65,47 +64,62 @@ export const MATChartWrapper = ({ link, caption }) => {
...searchParams,
}
- return !!searchParams &&
-
-
- {caption && (
-
- {captionText}
-
- )}
-
+ return (
+ !!searchParams && (
+
+
+ {caption && (
+
+ {captionText}
+
+ )}
+
+ )
+ )
}
const MATChart = ({ query, showFilters = true }) => {
const intl = useIntl()
- const { data, error, isValidating } = useSWR(query ? query : null, fetcher, swrOptions)
+ const { data, error, isValidating } = useSWR(
+ query ? query : null,
+ fetcher,
+ swrOptions,
+ )
const showLoadingIndicator = useMemo(() => isValidating, [isValidating])
return (
-
+ <>
{error && }
-
+ <>
{showLoadingIndicator ? (
-
- {intl.formatMessage({ id: 'General.Loading' })}
-
+ {intl.formatMessage({ id: 'General.Loading' })}
) : (
<>
- {data?.data?.result?.length > 0 ?
-
- {data && data.data.dimension_count == 0 && }
- {data && data.data.dimension_count == 1 && }
+ {data?.data?.result?.length > 0 ? (
+ <>
+ {data && data.data.dimension_count === 0 && (
+
+ )}
+ {data && data.data.dimension_count === 1 && (
+
+ )}
{data && data.data.dimension_count > 1 && (
-
+
)}
- :
- }
+ >
+ ) : (
+
+ )}
>
)}
-
+ >
-
+ >
)
}
diff --git a/components/NavBar.js b/components/NavBar.js
index d3e4e20b5..ea40a0da1 100644
--- a/components/NavBar.js
+++ b/components/NavBar.js
@@ -1,129 +1,63 @@
import useUser from 'hooks/useUser'
-import NLink from 'next/link'
+import Link from 'next/link'
import { useRouter } from 'next/router'
-import { Box, Container, Flex } from 'ooni-components'
import ExplorerLogo from 'ooni-components/svgs/logos/Explorer-HorizontalMonochromeInverted.svg'
-import React, { useEffect, useState } from 'react'
+import { useEffect, useState } from 'react'
import { MdClose, MdMenu } from 'react-icons/md'
import { FormattedMessage, useIntl } from 'react-intl'
-import styled from 'styled-components'
import { getLocalisedLanguageName } from 'utils/i18nCountries'
import { getDirection } from './withIntl'
-const StyledNavItem = styled(NLink)`
- position: relative;
- color: ${(props) => props.theme.colors.white};
- cursor: pointer;
- padding-bottom: ${(props) => (props.$active ? '4px' : '6px')};
- opacity: ${(props) => (props.$active ? '1' : '0.6')};
- border-bottom: ${(props) => (props.$active ? `2px solid ${props.theme.colors.white}` : 'none')};
-
- &:hover {
- padding-bottom: 4px;
- color: ${(props) => props.theme.colors.white};
- opacity: 1;
- border-bottom: 2px solid ${(props) => props.theme.colors.white};
- }
-`
-
-const LanguageSelect = styled.select`
-color: ${(props) => props.theme.colors.white};
-background: none;
-opacity: 0.6;
-border: none;
-text-transform: capitalize;
-cursor: pointer;
-font-family: inherit;
-font-size: inherit;
-padding: 0;
-padding-bottom: 6px;
-outline: none;
-appearance: none;
--webkit-appearance: none;
--moz-appearance: none;
--ms-appearance: none;
--o-appearance: none;
-&:hover {
- opacity: 1;
-}
-// reset option styling for browsers that apply it to its native styling (Brave)
-> option {
- color: initial;
- opacity: initial;
-}
-`
-
-const NavItem = ({ label, href, ...rest }) => {
+const LanguageSelect = (props) => (
+
+)
+
+const StyledNavItem = ({ isActive, ...props }) => (
+
+)
+
+const NavItem = ({ label, href, ...props }) => {
const { pathname } = useRouter()
const [isActive, setIsActive] = useState(false)
-
+
useEffect(() => {
setIsActive(pathname === href)
}, [pathname, href])
return (
-
{label}
+
+ {label}
+
)
}
-const StyledNavBar = styled.div`
- background-color: ${(props) => props.$bgColor || props.theme.colors.blue5};
- padding-top: 16px;
- padding-bottom: 20px;
- z-index: 9999;
-`
-
-const StyledResponsiveMenu = styled(Box)`
-.menuIcon,
-.closeIcon {
- display: none;
-}
-
-@media screen and (max-width: 948px) {
- .menuIcon,
- .closeIcon {
- display: block;
- cursor: pointer;
- }
-
- .closeIcon {
- color: ${(props) => props.theme.colors.black};
- }
-
- .menuItemsWrapper {
- display: none;
-
- &.visible {
- z-index: 999999;
- display: block;
- overflow-y: scroll;
- max-height: 100%;
- padding: ${(props) => props.theme.space[4]}px;
- font-Size: 16px;
- position: fixed;
- top: 0;
- right: 0;
- background: ${(props) => props.theme.colors.gray0};
-
- .menuItems {
- padding-top: ${(props) => props.theme.space[2]}px;
- flex-direction: column;
- align-items: start;
-
- a {
- border-color: ${(props) => props.theme.colors.black};
- }
-
- a, select {
- opacity: 1;
- color: ${(props) => props.theme.colors.black};
- }
- }
- }
- }
-}
-`
-
const languages = process.env.LOCALES
export const NavBar = ({ color }) => {
@@ -146,51 +80,98 @@ export const NavBar = ({ color }) => {
logout()
}
+ // biome-ignore lint/correctness/useExhaustiveDependencies:
useEffect(() => {
setShowMenu(false)
}, [pathname])
return (
-
-
-
-
-
-
-
-
-
- setShowMenu(!showMenu)} />
-
+
+
+
+
+
+
+
+
+
+
setShowMenu(!showMenu)}
+ />
+
{showMenu && (
-
- setShowMenu(!showMenu)} />
-
+
+ setShowMenu(!showMenu)}
+ />
+
)}
-
- } href="/search" data-umami-event="navigation-search" />
- } href="/chart/mat" data-umami-event="navigation-mat" />
- } href="/chart/circumvention" data-umami-event="navigation-circumvention" />
- } href="/countries" data-umami-event="navigation-countries" />
- } href="/networks" data-umami-event="navigation-networks" />
- } href="/domains" data-umami-event="navigation-domains" />
- } href="/findings" data-umami-event="navigation-findings" />
+ a]:border-black [&>a]:hover:border-black [&>*]:opacity-100 [&>*]:text-black [&>*]:hover:text-black'}`}
+ >
+ }
+ href="/search"
+ data-umami-event="navigation-search"
+ />
+ }
+ href="/chart/mat"
+ data-umami-event="navigation-mat"
+ />
+ }
+ href="/chart/circumvention"
+ data-umami-event="navigation-circumvention"
+ />
+ }
+ href="/countries"
+ data-umami-event="navigation-countries"
+ />
+ }
+ href="/networks"
+ data-umami-event="navigation-networks"
+ />
+ }
+ href="/domains"
+ data-umami-event="navigation-domains"
+ />
+ }
+ href="/findings"
+ data-umami-event="navigation-findings"
+ />
{user?.logged_in && (
-
+
+
+
)}
{languages.map((c) => (
-
+
{getLocalisedLanguageName(c, c)}
))}
-
-
-
-
-
-
+
+
+
+
+
+
)
}
diff --git a/components/NotFound.js b/components/NotFound.js
index e3e599982..dc100abc0 100644
--- a/components/NotFound.js
+++ b/components/NotFound.js
@@ -1,25 +1,19 @@
-/* global process */
-import React from 'react'
-import { Container, Flex, Box, Heading, Text } from 'ooni-components'
import { useRouter } from 'next/router'
-
import OONI404 from '../public/static/images/OONI_404.svg'
-import { useIntl } from 'react-intl'
const NotFound = ({ title }) => {
const { asPath } = useRouter()
- const intl = useIntl()
return (
-
-
+
+
-
- {title}
- {`${process.env.NEXT_PUBLIC_EXPLORER_URL}${asPath}`}
-
-
-
+
+
{title}
+
{`${process.env.NEXT_PUBLIC_EXPLORER_URL}${asPath}`}
+
+
+
)
}
diff --git a/components/SharedStyledComponents.js b/components/SharedStyledComponents.js
index 90ab5560a..289fc97b2 100644
--- a/components/SharedStyledComponents.js
+++ b/components/SharedStyledComponents.js
@@ -1,53 +1,28 @@
-import { Box, Button, Container, Flex, Heading } from 'ooni-components'
-import styled from 'styled-components'
+export const StyledSticky = ({ ...props }) => (
+
+)
-export const StyledSticky = styled.div`
-position: sticky;
-top: 0;
-background: white;
-z-index: 99;
-border-bottom: 1px solid ${props => props.theme.colors.gray3};
-`
+export const StyledStickyNavBar = ({ ...props }) => (
+
+)
-export const StyledStickyNavBar = styled.div`
-position: sticky;
-top: 0;
-z-index: 100;
-`
-
-export const StyledStickySubMenu = styled(Box)`
-position: sticky;
-top: 65.5px;
-background: white;
-z-index: 99;
-border-bottom: 1px solid ${props => props.theme.colors.gray3};
-`
+export const StyledStickySubMenu = ({ ...props }) => (
+
+)
export const StickySubMenu = ({ title, children }) => {
return (
-
-
-
- {title}
-
-
- {children}
-
-
+
+
+
{title}
+ {children}
+
)
}
-
-// port the design to ooni-components
-export const StyledHollowButton = styled(Button)`
-&:hover {
- border-color: ${props => props.theme.colors.blue9};
- color: ${props => props.theme.colors.blue9};
- &:hover:enabled {
- border-color: ${props => props.theme.colors.blue9};
- }
-}
-`
-StyledHollowButton.defaultProps = {
- hollow: true
-}
\ No newline at end of file
diff --git a/components/SocialButtons.js b/components/SocialButtons.js
index 359434c71..d33063736 100644
--- a/components/SocialButtons.js
+++ b/components/SocialButtons.js
@@ -1,30 +1,46 @@
-import React from 'react'
import PropTypes from 'prop-types'
-import { Link, Flex, Text } from 'ooni-components'
import { MdShare } from 'react-icons/md'
import { useIntl } from 'react-intl'
const SocialButtons = ({ url }) => {
const intl = useIntl()
- return(
-
-
-
+ return (
+
+
+
{intl.formatMessage(
- {id: 'SocialButtons.CTA'},
+ { id: 'SocialButtons.CTA' },
{
- 'facebook-link': (string) => (
{string}),
- 'twitter-link': (string) => (
{string})
- }
+ 'facebook-link': (string) => (
+
+ {string}
+
+ ),
+ 'twitter-link': (string) => (
+
+ {string}
+
+ ),
+ },
)}
-
-
+
+
)
}
SocialButtons.propTypes = {
- url: PropTypes.string.isRequired
+ url: PropTypes.string.isRequired,
}
export default SocialButtons
diff --git a/components/TestNameOptions.js b/components/TestNameOptions.js
index 11d2f6993..c25db641d 100644
--- a/components/TestNameOptions.js
+++ b/components/TestNameOptions.js
@@ -1,16 +1,16 @@
import { useIntl } from 'react-intl'
import { testGroups, testNames } from '../components/test-info'
-export const TestNameOptions = ({ includeAllOption = true}) => {
+export const TestNameOptions = ({ includeAllOption = true }) => {
const intl = useIntl()
- const groupedTestNameOptions = Object.entries(testNames)
- .reduce((grouped, [testKey, testValue]) => {
+ const groupedTestNameOptions = Object.entries(testNames).reduce(
+ (grouped, [testKey, testValue]) => {
const group = testValue.group
const option = {
id: testKey,
name: testValue.name,
intlKey: testValue.id,
- group
+ group,
}
if (group in grouped) {
grouped[group].push(option)
@@ -18,7 +18,9 @@ export const TestNameOptions = ({ includeAllOption = true}) => {
grouped[group] = [option]
}
return grouped
- }, {})
+ },
+ {},
+ )
const sortedGroupedTestNameOptions = new Map()
@@ -28,15 +30,26 @@ export const TestNameOptions = ({ includeAllOption = true}) => {
}
}
- return ([
+ return [
// Optinally insert an 'Any' option to test name filter
- includeAllOption && {intl.formatMessage({id: 'Search.Sidebar.TestName.AllTests'})} ,
+ includeAllOption && (
+
+ {intl.formatMessage({ id: 'Search.Sidebar.TestName.AllTests' })}
+
+ ),
[...sortedGroupedTestNameOptions].map(([group, tests]) => {
- const groupName = group in testGroups ? intl.formatMessage({id: testGroups[group].id}) : group
- const testOptions = tests.map(({id, name, intlKey}) => {
- return {intlKey ? intl.formatMessage({id: intlKey}) : name}
- })
+ const groupName =
+ group in testGroups
+ ? intl.formatMessage({ id: testGroups[group].id })
+ : group
+ const testOptions = tests.map(({ id, name, intlKey }) => {
+ return (
+
+ {intlKey ? intl.formatMessage({ id: intlKey }) : name}
+
+ )
+ })
return [ , ...testOptions]
- })
- ])
-}
\ No newline at end of file
+ }),
+ ]
+}
diff --git a/components/ThirdPartyDataChart.js b/components/ThirdPartyDataChart.js
index 42bd60753..5d4576cf1 100644
--- a/components/ThirdPartyDataChart.js
+++ b/components/ThirdPartyDataChart.js
@@ -1,43 +1,44 @@
-import { useState, useEffect, memo, useMemo } from 'react'
-import axios from 'axios'
import { ResponsiveLine } from '@nivo/line'
-import { Box, Flex, Text, Heading, theme } from 'ooni-components'
-import dayjs from 'services/dayjs'
+import axios from 'axios'
+import Slices from 'components/chart/Slices'
+import { colors } from 'ooni-components'
+import { memo, useEffect, useMemo, useState } from 'react'
import { useIntl } from 'react-intl'
+import dayjs from 'services/dayjs'
+import FormattedMarkdown from './FormattedMarkdown'
import SectionHeader from './country/SectionHeader'
import { SimpleBox } from './country/boxes'
-import FormattedMarkdown from './FormattedMarkdown'
-import Slices from 'components/chart/Slices'
const iodaLineColors = {
- gtr: theme.colors.blue5,
- 'merit-nt': theme.colors.red5,
- bgp: theme.colors.green5,
- 'ping-slash24': theme.colors.fuchsia5
+ gtr: colors.blue['500'],
+ 'merit-nt': colors.red['500'],
+ bgp: colors.green['500'],
+ 'ping-slash24': colors.fuchsia['500'],
}
-const SectionText = ({location, asn, country, from, until}) => {
+const SectionText = ({ location, asn, country, from, until }) => {
let dateParams = ''
if (from && until) {
- const formattedFrom = Math.round(dayjs(from).utc().valueOf()/1000)
- const formattedTo = Math.round(dayjs(until).utc().valueOf()/1000)
+ const formattedFrom = Math.round(dayjs(from).utc().valueOf() / 1000)
+ const formattedTo = Math.round(dayjs(until).utc().valueOf() / 1000)
dateParams = `?from=${formattedFrom}&until=${formattedTo})`
}
return (
- (`[${string}](https://ioda.inetintel.cc.gatech.edu/${country ? 'country' : 'asn'}/${location}${dateParams}`),
- 'cloudflare-link': (string) => (`[${string}](https://radar.cloudflare.com/${asn ? 'as' : ''}${location}?range=28d)`)
+ 'ioda-link': (string) =>
+ `[${string}](https://ioda.inetintel.cc.gatech.edu/${country ? 'country' : 'asn'}/${location}${dateParams}`,
+ 'cloudflare-link': (string) =>
+ `[${string}](https://radar.cloudflare.com/${asn ? 'as' : ''}${location}?range=28d)`,
}}
/>
)
}
-
-const ThirdPartyDataChart = ({since, until, country, asn, ...props}) => {
+const ThirdPartyDataChart = ({ since, until, country, asn, ...props }) => {
const intl = useIntl()
const location = country || asn
const [graphData, setGraphData] = useState([])
@@ -46,44 +47,60 @@ const ThirdPartyDataChart = ({since, until, country, asn, ...props}) => {
const [from, to] = useMemo(() => {
if (!since || !until) return []
// make sure the date is not in the future to avoid receiving error from CloudFlare
- const to = dayjs(until).isBefore(dayjs(), 'day') ?
- dayjs.utc(until).toISOString() :
- dayjs().subtract(30, 'minute').utc().toISOString()
+ const to = dayjs(until).isBefore(dayjs(), 'day')
+ ? dayjs.utc(until).toISOString()
+ : dayjs().subtract(30, 'minute').utc().toISOString()
const from = dayjs.utc(since).toISOString()
return [from, to]
}, [since, until])
const cloudflareData = useEffect(() => {
- if (!since && !until) return
-
+ if (!since && !until) return
+
setGraphData([])
setError(null)
Promise.allSettled([
- axios.get(`/api/cloudflare?from=${from}&to=${to}&${asn ? `asn=${asn}` : `country=${country}`}`),
- axios.get(`/api/ioda?from=${from}&to=${to}&${asn ? `asn=${asn}` : `country=${country}`}`)
- ]).then((results) => {
- const cloudflareData = results[0]
- const iodaData = results[1]
+ axios.get(
+ `/api/cloudflare?from=${from}&to=${to}&${asn ? `asn=${asn}` : `country=${country}`}`,
+ ),
+ axios.get(
+ `/api/ioda?from=${from}&to=${to}&${asn ? `asn=${asn}` : `country=${country}`}`,
+ ),
+ ])
+ .then((results) => {
+ const cloudflareData = results[0]
+ const iodaData = results[1]
- const cloudflareChartData = cloudflareData.status === 'fulfilled' ?
- [{
- 'id': intl.formatMessage({id:'ThirdPartyChart.Label.cloudflare'}),
- 'color': theme.colors.yellow5,
- 'data': cloudflareData.value.data,
- }] : []
+ const cloudflareChartData =
+ cloudflareData.status === 'fulfilled'
+ ? [
+ {
+ id: intl.formatMessage({
+ id: 'ThirdPartyChart.Label.cloudflare',
+ }),
+ color: colors.yellow['500'],
+ data: cloudflareData.value.data,
+ },
+ ]
+ : []
- const iodaChartData = iodaData.status === 'fulfilled' ?
- iodaData.value.data.map((item) => {
- return {
- 'id': intl.formatMessage({id: `ThirdPartyChart.Label.${item.datasource}`}),
- 'color': iodaLineColors[item.datasource],
- 'data': item.values
- }
- }) : []
+ const iodaChartData =
+ iodaData.status === 'fulfilled'
+ ? iodaData.value.data.map((item) => {
+ return {
+ id: intl.formatMessage({
+ id: `ThirdPartyChart.Label.${item.datasource}`,
+ }),
+ color: iodaLineColors[item.datasource],
+ data: item.values,
+ }
+ })
+ : []
- setGraphData([...iodaChartData, ...cloudflareChartData])
- }).catch((err) => {})
+ setGraphData([...iodaChartData, ...cloudflareChartData])
+ })
+ .catch((err) => {})
}, [since, until])
return (
@@ -92,25 +109,37 @@ const ThirdPartyDataChart = ({since, until, country, asn, ...props}) => {
{country ? (
<>
-
- {intl.formatMessage({id: 'Country.Outages'})}
+
+ {intl.formatMessage({ id: 'Country.Outages' })}
-
-
-
+
+
+
>
) : (
<>
- {intl.formatMessage({id: 'Country.Outages'})}
-
+ {intl.formatMessage({ id: 'Country.Outages' })}
+
>
)}
-
- {!!graphData.length && !error &&
+
+ {!!graphData.length && !error && (
{
type: 'linear',
stacked: false,
min: 0,
- max: 1
+ max: 1,
}}
axisBottom={{
format: '%Y-%m-%d',
}}
- enableSlices='x'
- colors={d => d.color}
- layers={[
- 'grid',
- 'axes',
- 'lines',
- 'legends',
- 'crosshair',
- Slices,
- ]}
+ enableSlices="x"
+ colors={(d) => d.color}
+ layers={['grid', 'axes', 'lines', 'legends', 'crosshair', Slices]}
sliceTooltip={(props) => {
if (props?.slice?.points?.length) {
const points = props.slice.points
@@ -152,10 +174,16 @@ const ThirdPartyDataChart = ({since, until, country, asn, ...props}) => {
border: '1px solid #ccc',
}}
>
- {new Intl.DateTimeFormat(intl.locale, { dateStyle: 'long', timeStyle: 'long', timeZone: 'UTC' }).format(new Date(points[0].data.x))}
+
+ {new Intl.DateTimeFormat(intl.locale, {
+ dateStyle: 'long',
+ timeStyle: 'long',
+ timeZone: 'UTC',
+ }).format(new Date(points[0].data.x))}
+
{points.map((point) => (
-
-
+ {
height: '10px',
}}
/>
-
{point.serieId} [{Number(point.data.yFormatted).toFixed(4)}]
-
+
+ {point.serieId} [
+ {Number(point.data.yFormatted).toFixed(4)}]
+
+
))}
)
@@ -182,16 +213,16 @@ const ThirdPartyDataChart = ({since, until, country, asn, ...props}) => {
itemHeight: 20,
symbolSize: 12,
symbolShape: 'circle',
- }
+ },
]}
/>
- }
- {error &&
- Unable to retrieve the data
- }
-
+ )}
+ {error && (
+ Unable to retrieve the data
+ )}
+
>
)
}
-export default memo(ThirdPartyDataChart)
\ No newline at end of file
+export default memo(ThirdPartyDataChart)
diff --git a/components/VictoryTheme.js b/components/VictoryTheme.js
index 2f43cb67b..14c674b2c 100644
--- a/components/VictoryTheme.js
+++ b/components/VictoryTheme.js
@@ -1,19 +1,18 @@
-import { theme } from 'ooni-components'
+import { colors } from 'ooni-components'
import { firaSans } from '../pages/_app'
-const colors = theme.colors
// Color scale
const colorScale = [
- colors.yellow2,
- colors.lime3,
- colors.fuschia4,
- colors.blue5,
- colors.grey6,
- colors.grey7,
- colors.green8
+ colors.yellow['200'],
+ colors.lime['300'],
+ colors.fuchsia['400'],
+ colors.blue['500'],
+ colors.gray['600'],
+ colors.gray['700'],
+ colors.green['800'],
]
-const primaryColor = colors.base
+const primaryColor = colors.blue['500']
// Typography
export const sansSerif = `${firaSans.style.fontFamily}, sans-serif`
@@ -23,7 +22,7 @@ const fontSize = 8
// Layout
const baseProps = {
colorScale: colorScale,
- overflow: 'visible'
+ overflow: 'visible',
}
// Labels
@@ -36,7 +35,10 @@ export const baseLabelStyles = {
stroke: 'transparent',
}
-const centeredLabelStyles = Object.assign({ textAnchor: 'middle' }, baseLabelStyles)
+const centeredLabelStyles = Object.assign(
+ { textAnchor: 'middle' },
+ baseLabelStyles,
+)
// Strokes
const strokeDasharray = '1, 3'
@@ -49,28 +51,31 @@ export const axisYStyle = {
strokeOpacity: '0.5',
strokeDasharray,
strokeLinecap,
- strokeLinejoin
+ strokeLinejoin,
},
axis: {
fill: 'transparent',
- stroke: 'transparent'
+ stroke: 'transparent',
},
- axisLabel: Object.assign({}, centeredLabelStyles, {padding: 25}),
+ axisLabel: Object.assign({}, centeredLabelStyles, { padding: 25 }),
ticks: {
fill: 'transparent',
- stroke: 'transparent'
+ stroke: 'transparent',
},
}
const victoryTheme = {
- area: Object.assign({
- style: {
- data: {
- fill: primaryColor
+ area: Object.assign(
+ {
+ style: {
+ data: {
+ fill: primaryColor,
+ },
+ labels: centeredLabelStyles,
},
- labels: centeredLabelStyles
- }
- }, baseProps),
+ },
+ baseProps,
+ ),
axis: Object.assign({}, baseProps, {
style: {
@@ -79,136 +84,158 @@ const victoryTheme = {
stroke: colors.black,
strokeWidth: 1,
strokeLinecap,
- strokeLinejoin
+ strokeLinejoin,
},
- axisLabel: Object.assign({}, centeredLabelStyles, {padding: 25}),
+ axisLabel: Object.assign({}, centeredLabelStyles, { padding: 25 }),
grid: {
fill: 'transparent',
stroke: 'transparent',
- pointerEvents: 'none'
+ pointerEvents: 'none',
},
ticks: {
fill: 'transparent',
size: 5,
- stroke: colors.black
+ stroke: colors.black,
},
- tickLabels: baseLabelStyles
- }
+ tickLabels: baseLabelStyles,
+ },
}),
- bar: Object.assign({
- style: {
- data: {
- fill: primaryColor,
- padding: 8,
- strokeWidth: 0
- },
- labels: baseLabelStyles,
- }
- }, baseProps),
-
- candlestick: Object.assign({
- style: {
- data: {
- stroke: primaryColor,
- strokeWidth: 1
+ bar: Object.assign(
+ {
+ style: {
+ data: {
+ fill: primaryColor,
+ padding: 8,
+ strokeWidth: 0,
+ },
+ labels: baseLabelStyles,
},
- labels: centeredLabelStyles
},
- candleColors: {
- positive: '#ffffff',
- negative: primaryColor
+ baseProps,
+ ),
+
+ candlestick: Object.assign(
+ {
+ style: {
+ data: {
+ stroke: primaryColor,
+ strokeWidth: 1,
+ },
+ labels: centeredLabelStyles,
+ },
+ candleColors: {
+ positive: '#ffffff',
+ negative: primaryColor,
+ },
},
- }, baseProps),
+ baseProps,
+ ),
chart: baseProps,
- errorbar: Object.assign({
- style: {
- data: {
- fill: 'transparent',
- stroke: primaryColor,
- strokeWidth: 2
+ errorbar: Object.assign(
+ {
+ style: {
+ data: {
+ fill: 'transparent',
+ stroke: primaryColor,
+ strokeWidth: 2,
+ },
+ labels: centeredLabelStyles,
},
- labels: centeredLabelStyles
},
- }, baseProps),
-
- group: Object.assign({
- colorScale: colorScale,
- }, baseProps),
+ baseProps,
+ ),
- line: Object.assign({
- style: {
- data: {
- fill: 'transparent',
- stroke: primaryColor,
- strokeWidth: 2
+ group: Object.assign(
+ {
+ colorScale: colorScale,
+ },
+ baseProps,
+ ),
+
+ line: Object.assign(
+ {
+ style: {
+ data: {
+ fill: 'transparent',
+ stroke: primaryColor,
+ strokeWidth: 2,
+ },
+ labels: centeredLabelStyles,
},
- labels: centeredLabelStyles}
- }, baseProps),
+ },
+ baseProps,
+ ),
pie: {
style: {
data: {
padding: 10,
stroke: 'transparent',
- strokeWidth: 1
+ strokeWidth: 1,
},
- labels: Object.assign({padding: 20}, baseLabelStyles)
+ labels: Object.assign({ padding: 20 }, baseLabelStyles),
},
colorScale: colorScale,
width: 400,
height: 400,
- padding: 50
+ padding: 50,
},
- scatter: Object.assign({
- style: {
- data: {
- fill: primaryColor,
- stroke: 'transparent',
- strokeWidth: 0
+ scatter: Object.assign(
+ {
+ style: {
+ data: {
+ fill: primaryColor,
+ stroke: 'transparent',
+ strokeWidth: 0,
+ },
+ labels: centeredLabelStyles,
},
- labels: centeredLabelStyles
},
- }, baseProps),
+ baseProps,
+ ),
- stack: Object.assign({colorScale: colorScale}, baseProps),
+ stack: Object.assign({ colorScale: colorScale }, baseProps),
tooltip: {
style: Object.assign({}, centeredLabelStyles, {
padding: 5,
- pointerEvents: 'none'
+ pointerEvents: 'none',
}),
flyoutStyle: {
stroke: primaryColor,
strokeWidth: 1,
- pointerEvents: 'none'
+ pointerEvents: 'none',
},
cornerRadius: 5,
- pointerLength: 10
+ pointerLength: 10,
},
- voronoi: Object.assign({
- style: {
- data: {
- fill: 'transparent',
- stroke: 'transparent',
- strokeWidth: 0
+ voronoi: Object.assign(
+ {
+ style: {
+ data: {
+ fill: 'transparent',
+ stroke: 'transparent',
+ strokeWidth: 0,
+ },
+ labels: Object.assign({}, centeredLabelStyles, {
+ padding: 5,
+ pointerEvents: 'none',
+ }),
+ flyout: {
+ stroke: primaryColor,
+ strokeWidth: 1,
+ fill: '#f0f0f0',
+ pointerEvents: 'none',
+ },
},
- labels: Object.assign({}, centeredLabelStyles, {
- padding: 5,
- pointerEvents: 'none'
- }),
- flyout: {
- stroke: primaryColor,
- strokeWidth: 1,
- fill: '#f0f0f0',
- pointerEvents: 'none'
- }
- }
- }, baseProps),
+ },
+ baseProps,
+ ),
legend: {
colorScale: colorScale,
@@ -216,11 +243,11 @@ const victoryTheme = {
orientation: 'vertical',
style: {
data: {
- type: 'circle'
+ type: 'circle',
},
- labels: baseLabelStyles
+ labels: baseLabelStyles,
},
- symbolSpacer: 8
- }
+ symbolSpacer: 8,
+ },
}
export default victoryTheme
diff --git a/components/VirtualizedGrid.js b/components/VirtualizedGrid.js
index 49118c6da..f35c305ba 100644
--- a/components/VirtualizedGrid.js
+++ b/components/VirtualizedGrid.js
@@ -1,68 +1,54 @@
-import NLink from 'next/link'
-import { Box, Flex, Text } from 'ooni-components'
-import React from 'react'
+import Link from 'next/link'
import { FormattedMessage } from 'react-intl'
import { AutoSizer, List, WindowScroller } from 'react-virtualized'
-import styled from 'styled-components'
-const StyledLink = styled(NLink)`
-&:hover {
- filter: none;
-}
-`
-
-const StyledName = styled(Text)`
-`
-
-const StyledFlex = styled(Flex)`
-border: 1px solid ${props => props.theme.colors.gray3};
-position: relative;
-color: black;
-flex-flow: column;
-
-&:hover {
- border-color: ${props => props.theme.colors.blue5};
- ${StyledName} {
- color: ${props => props.theme.colors.blue5};
- }
-}
-`
-
-export const GridBox = ({ title, count = null, href, tag, multiCount = null }) => {
+export const GridBox = ({
+ title,
+ count = null,
+ href,
+ tag,
+ multiCount = null,
+}) => {
const hasCount = Number.isInteger(count)
+
return (
-