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

Add thematic pages #970

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
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
Next Next commit
Add thematic pages
majakomel committed Mar 20, 2025
commit 6c78a232993fd0b11a41e2a7432d4c1a5c56eeb9
4 changes: 2 additions & 2 deletions .env.development
Original file line number Diff line number Diff line change
@@ -2,8 +2,8 @@
# To override locally, make a copy called `.env.development.local`
# Refer: https://nextjs.org/docs/basic-features/environment-variables

NEXT_PUBLIC_OONI_API=https://backend-hel.ooni.org
NEXT_PUBLIC_USER_FEEDBACK_API=https://backend-hel.ooni.org
NEXT_PUBLIC_OONI_API=https://api.ooni.org
NEXT_PUBLIC_USER_FEEDBACK_API=https://api.dev.ooni.io
NEXT_PUBLIC_EXPLORER_URL=http://localhost:3100

RUN_GIT_COMMIT_SHA_SHORT=yarn --silent git:getCommitSHA:short
4 changes: 2 additions & 2 deletions .env.test
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
# To override locally, make a copy called `.env.test.local`
# Refer: https://nextjs.org/docs/basic-features/environment-variables

NEXT_PUBLIC_OONI_API=https://api.ooni.io
NEXT_PUBLIC_USER_FEEDBACK_API=https://backend-hel.ooni.org
NEXT_PUBLIC_OONI_API=https://api.ooni.org
NEXT_PUBLIC_USER_FEEDBACK_API=https://api.dev.ooni.io
NEXT_PUBLIC_EXPLORER_URL=https://explorer.test.ooni.org
NEXT_PUBLIC_IS_TEST_ENV=1
2 changes: 1 addition & 1 deletion components/BlockText.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const BlockText = ({ className, ...props }) => (
<div
className={`bg-gray-50 border-s-[10px] text-base border-blue-500 p-3 font-base ${className}`}
className={`bg-gray-50 border-s-[10px] border-blue-500 p-3 font-base ${className}`}
{...props}
/>
)
28 changes: 17 additions & 11 deletions components/Chart.js
Original file line number Diff line number Diff line change
@@ -58,11 +58,19 @@ export const MATLink = ({ query }) => {
)
}

const Chart = memo(function Chart({
testGroup = null,
queryParams = {},
setState,
}) {
export const ChartSpinLoader = ({ height = '300px' }) => {
return (
<div
className="bg-gray-100 flex items-center justify-center p-6"
style={{ height }}
>
{/* <FormattedMessage id="General.Loading" /> */}
<SpinLoader />
</div>
)
}

const Chart = ({ queryParams = {}, setState = null, headerOptions = {} }) => {
const apiQuery = useMemo(() => {
const qs = new URLSearchParams(queryParams).toString()
return qs
@@ -87,20 +95,18 @@ const Chart = memo(function Chart({
if (setState && data?.data) setState(data.data)
}, [data, setState])

const headerOptions = { probe_cc: false, subtitle: false }

return (
// <MATContextProvider key={name} test_name={name} {...queryParams}>
<MATContextProvider {...queryParams}>
<div className="flex flex-col">
{!chartData && !error ? (
<FormattedMessage id="General.Loading" />
<ChartSpinLoader />
) : (
<>
<GridChart
data={chartData}
rowKeys={rowKeys}
rowLabels={rowLabels}
header={headerOptions}
/>
{!!chartData?.size && <MATLink query={queryParams} />}
</>
@@ -120,6 +126,6 @@ const Chart = memo(function Chart({
</div>
</MATContextProvider>
)
})
}

export default Chart
export default memo(Chart)
59 changes: 59 additions & 0 deletions components/ChartWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import Chart, { ChartSpinLoader } from 'components/Chart'
import { useRouter } from 'next/router'
import { useMemo } from 'react'
import { useInView } from 'react-intersection-observer'

type ChartWrapperProps = {
domain?: string
testName?: string
headerOptions?: object
}

const ChartWrapper = ({
domain,
testName = 'web_connectivity',
headerOptions,
}: ChartWrapperProps) => {
const router = useRouter()

const {
query: { since, until, probe_cc },
} = router

const query = useMemo(
() => ({
axis_x: 'measurement_start_day',
axis_y: 'probe_cc',
since,
until,
test_name: testName,
...(domain && { domain }),
...(probe_cc && { probe_cc }),
time_grain: 'day',
}),
[domain, since, until, probe_cc, testName],
)

const { ref, inView } = useInView({
triggerOnce: true,
rootMargin: '-300px 0px 0px 0px',
threshold: 0.5,
initialInView: false,
})

return (
<div ref={ref}>
{inView ? (
<Chart
// testName={testName}
queryParams={query}
headerOptions={headerOptions}
/>
) : (
<ChartSpinLoader />
)}
</div>
)
}

export default ChartWrapper
2 changes: 0 additions & 2 deletions components/DomainChart.js
Original file line number Diff line number Diff line change
@@ -52,11 +52,9 @@ const Chart = memo(function Chart({ queryParams = {}, setState }) {
if (setState && data?.data) setState(data.data)
}, [data, setState])

const headerOptions = { probe_cc: false, subtitle: false }
const linkParams = { ...queryParams, ...(probe_cc && { probe_cc }) }

return (
// <MATContextProvider key={name} test_name={name} {...queryParams}>
<MATContextProvider {...queryParams}>
<div className="flex flex-col">
<div>
44 changes: 44 additions & 0 deletions components/FindingsSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { FindingBox } from 'components/landing/HighlightBox'
import Link from 'next/link'

interface Finding {
id: string
}

type FindingsSectionProps = {
title: string
theme: string
findings: Finding[]
}

const FindingsSection = ({
title,
theme,
findings = [],
}: FindingsSectionProps) => {
return (
<section className="mb-12">
<h3>{title}</h3>
{findings.length ? (
<>
<div className="grid my-8 gap-6 grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
{findings.map((finding) => (
<FindingBox key={finding.id} incident={finding} />
))}
</div>
<div className="flex my-4 justify-center">
<Link href={`/findings?theme=${theme}`}>
<button type="button" className="btn btn-primary-hollow">
See more
</button>
</Link>
</div>
</>
) : (
<div className="my-3">No findings available</div>
)}
</section>
)
}

export default FindingsSection
4 changes: 4 additions & 0 deletions components/Layout.js
Original file line number Diff line number Diff line change
@@ -24,6 +24,10 @@ const Layout = ({ children, isEmbeddedView }) => {
return (
pathname === '/countries' ||
pathname === '/domains' ||
pathname === '/human-rights' ||
pathname === '/social-media' ||
pathname === '/news-media' ||
pathname === '/circumvention' ||
pathname === '/networks' ||
pathname === '/findings' ||
pathname.match(/^\/country\/\S+/)
55 changes: 28 additions & 27 deletions components/MATChart.js
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ import { useMemo } from 'react'
import { useIntl } from 'react-intl'
import dayjs from 'services/dayjs'
import useSWR from 'swr'
import { ChartSpinLoader } from './Chart'
import { FormattedMarkdownBase } from './FormattedMarkdown'

axiosResponseTime(axios)
@@ -87,37 +88,37 @@ const MATChart = ({ query, showFilters = true }) => {
)

const showLoadingIndicator = useMemo(() => isValidating, [isValidating])

return (
<>
<MATContextProvider queryParams={query}>
{error && <NoCharts message={error?.info ?? JSON.stringify(error)} />}
<>
{showLoadingIndicator ? (
<h2>{intl.formatMessage({ id: 'General.Loading' })}</h2>
) : (
<>
{data?.data?.result?.length > 0 ? (
<>
{data && data.data.dimension_count === 0 && (
<FunnelChart data={data.data.result} />
)}
{data && data.data.dimension_count === 1 && (
<StackedBarChart data={data.data.result} query={query} />
)}
{data && data.data.dimension_count > 1 && (
<TableView
data={data.data.result}
query={query}
showFilters={showFilters}
/>
)}
</>
) : (
<NoCharts />
)}
</>
)}
</>
{showLoadingIndicator ? (
// <h2>{intl.formatMessage({ id: 'General.Loading' })}</h2>
<ChartSpinLoader height={580} />
) : (
<>
{data?.data?.result?.length > 0 ? (
<>
{data && data.data.dimension_count === 0 && (
<FunnelChart data={data.data.result} />
)}
{data && data.data.dimension_count === 1 && (
<StackedBarChart data={data.data.result} query={query} />
)}
{data && data.data.dimension_count > 1 && (
<TableView
data={data.data.result}
query={query}
showFilters={showFilters}
/>
)}
</>
) : (
<NoCharts />
)}
</>
)}
</MATContextProvider>
</>
)
23 changes: 19 additions & 4 deletions components/NavBar.js
Original file line number Diff line number Diff line change
@@ -83,8 +83,23 @@ const SubMenu = () => {

const menuItem = [
{
label: <FormattedMessage id="Navbar.Charts.Circumvention" />,
href: '/chart/circumvention',
label: <FormattedMessage id="Navbar.SocialMedia" />,
href: '/social-media',
umami: 'navigation-social-media',
},
{
label: <FormattedMessage id="Navbar.NewsMedia" />,
href: '/news-media',
umami: 'navigation-news-media',
},
// {
// label: <FormattedMessage id="Navbar.HumanRights" />,
// href: '/human-rights',
// umami: 'navigation-human-rights',
// },
{
label: <FormattedMessage id="Navbar.Circumvention" />,
href: '/circumvention',
umami: 'navigation-circumvention',
},
{
@@ -170,7 +185,7 @@ export const NavBar = ({ color }) => {
onClick={() => setShowMenu(!showMenu)}
/>
<div
className={`z-[9999] lg:block ${showMenu ? 'block overflow-y-scroll max-h-full p-8 text-base fixed top-0 right-0 bg-gray-50' : 'hidden'}`}
className={`z-[9999] lg:block ${showMenu ? 'block overflow-y-scroll max-h-full p-8 fixed top-0 right-0 bg-gray-50' : 'hidden'}`}
>
{showMenu && (
<div className="flex justify-end">
@@ -191,7 +206,7 @@ export const NavBar = ({ color }) => {
/>
<NavItem
label={<FormattedMessage id="Navbar.Censorship" />}
href="/chart/circumvention"
href="/social-media"
data-umami-event="navigation-censorship"
/>
<NavItem
26 changes: 26 additions & 0 deletions components/ReportsSection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { FormattedMessage } from 'react-intl'
import { FeaturedArticle } from './country/Overview'
import { BoxWithTitle } from './country/boxes'

const ReportsSection = ({ title, reports }) => {
return (
<BoxWithTitle title={title}>
{/* <section className="my-12"> */}
{/* <h3>{title}</h3> */}
{reports?.length === 0 ? (
<FormattedMessage id="Country.Overview.FeaturedResearch.None" />
) : (
<ul>
{reports?.map((article, index) => (
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
<li key={index}>
<FeaturedArticle link={article.href} title={article.title} />
</li>
))}
</ul>
)}
</BoxWithTitle>
)
}

export default ReportsSection
16 changes: 16 additions & 0 deletions components/SharedStyledComponents.js
Original file line number Diff line number Diff line change
@@ -16,6 +16,22 @@ export const StyledStickySubMenu = ({ topClass, ...props }) => (
/>
)

export const StickySubMenuUpdated = ({ title, menu, topClass, ...props }) => {
return (
<div
className={`${topClass ? topClass : 'top-[62px]'} sticky bg-white z-[99] border-b border-gray-300 md:mt-8 mb-2 pb-2 md:pb-0`}
{...props}
>
<div className="flex justify-between items-start md:items-center flex-col md:flex-row">
<h1 className="mt-1">{title}</h1>
<div className="flex flex-col md:flex-row justify-start md:justify-end items-start md:items-center">
<div className="flex flex-row flex-wrap gap-4">{menu}</div>
</div>
</div>
</div>
)
}

export const StickySubMenu = ({ title, children, topClass }) => {
return (
<StyledStickySubMenu topClass={topClass}>
Loading