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 fallback for explorer index page thumbnails #4236

Merged
merged 3 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions packages/@ourworldindata/types/src/domainTypes/Various.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export enum SiteFooterContext {
multiDimDataPage = "multiDimDataPage",
dynamicCollectionPage = "dynamicCollectionPage",
explorerPage = "explorerPage",
explorerIndexPage = "explorerIndexPage",
default = "default",
dataInsightsIndexPage = "data-insights-index-page",
dataCatalogPage = "data-catalog-page",
Expand Down
86 changes: 86 additions & 0 deletions site/ExplorerIndex.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React from "react"
import ReactDOM from "react-dom"
import { MinimalExplorerInfo } from "@ourworldindata/types"
import { EXPLORER_DYNAMIC_THUMBNAIL_URL } from "../settings/clientSettings.js"
import { faHeartBroken } from "@fortawesome/free-solid-svg-icons"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { EXPLORERS_ROUTE_FOLDER } from "@ourworldindata/explorer"

function ExplorerIndexPageCard(props: {
baseUrl: string
explorer: MinimalExplorerInfo
}) {
const { baseUrl, explorer } = props
const [hasError, setHasError] = React.useState(false)
return (
<li key={explorer.slug}>
<a
className="explorer-index-page__card"
href={`${baseUrl}/${EXPLORERS_ROUTE_FOLDER}/${explorer.slug}`}
>
{!hasError ? (
<img
width="850"
height="600"
loading="lazy"
onError={() => setHasError(true)}
src={`${EXPLORER_DYNAMIC_THUMBNAIL_URL}/${explorer.slug}.png`}
/>
) : (
<div className="explorer-index-page__card-error">
<FontAwesomeIcon icon={faHeartBroken} />
<span>Explorer preview not available</span>
</div>
)}
<h2>{explorer.title}</h2>
<p>{explorer.subtitle}</p>
</a>
</li>
)
}

export interface ExplorerIndexPageProps {
baseUrl: string
explorers: MinimalExplorerInfo[]
}

export function ExplorerIndex(props: ExplorerIndexPageProps) {
const { baseUrl, explorers } = props
return (
<>
<header className="explorer-index-page__header grid grid-cols-12-full-width span-cols-14">
<h1 className="h1-semibold span-cols-12 col-start-2 collection-title">
Data Explorers
</h1>
<p className="span-cols-8 col-start-2 span-md-cols-12 col-md-start-2 body-2-regular collection-explanation">
Our data explorers gather many indicators together to
provide comprehensive overviews of their topics.
</p>
</header>
<ul className="explorer-index-page-list span-cols-12 col-start-2 grid grid-cols-4 grid-md-cols-2 grid-sm-cols-1">
{explorers.map((explorer) => (
<ExplorerIndexPageCard
baseUrl={baseUrl}
explorer={explorer}
key={explorer.slug}
/>
))}
</ul>
</>
)
}

export const __OWID_EXPLORER_INDEX_PAGE_PROPS =
"__OWID_EXPLORER_INDEX_PAGE_PROPS"

export function hydrateExplorerIndex() {
const explorerIndexPageProps = (window as any)[
__OWID_EXPLORER_INDEX_PAGE_PROPS
]

if (!explorerIndexPageProps) return
ReactDOM.hydrate(
<ExplorerIndex {...explorerIndexPageProps} />,
document.querySelector(".explorer-index-page")
)
}
27 changes: 27 additions & 0 deletions site/ExplorerIndexPage.scss
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
}
}
img {
background: $gray-5;
transition: 150ms;
box-shadow: 0px 0px 12px 0px rgba(49, 37, 2, 0.05);
}
Expand All @@ -55,4 +56,30 @@
}
}
}
@keyframes fadein {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.explorer-index-page__card-error {
width: 100%;
aspect-ratio: 850/600;
background-color: $gray-5;
color: $grey-text-color;
font-size: 1rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
svg {
margin-bottom: 16px;
}
svg,
p {
animation: fadein ease 0.3s;
}
}
}
54 changes: 18 additions & 36 deletions site/ExplorerIndexPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,23 @@ import { Html } from "./Html.js"
import { EXPLORERS_ROUTE_FOLDER } from "@ourworldindata/explorer"
import { SiteHeader } from "./SiteHeader.js"
import { SiteFooter } from "./SiteFooter.js"
import { MinimalExplorerInfo } from "@ourworldindata/types"
import { EXPLORER_DYNAMIC_THUMBNAIL_URL } from "../settings/clientSettings.js"

interface ExplorerIndexPageProps {
baseUrl: string
explorers: MinimalExplorerInfo[]
}
import { SiteFooterContext } from "@ourworldindata/types"
import {
__OWID_EXPLORER_INDEX_PAGE_PROPS,
ExplorerIndex,
ExplorerIndexPageProps,
} from "./ExplorerIndex.js"

export const ExplorerIndexPage = ({
baseUrl,
explorers,
}: ExplorerIndexPageProps) => {
const inlineJs = `window.${__OWID_EXPLORER_INDEX_PAGE_PROPS} = ${JSON.stringify(
{
baseUrl,
explorers,
}
)}`
return (
<Html>
<Head
Expand All @@ -27,36 +32,13 @@ export const ExplorerIndexPage = ({
<body>
<SiteHeader baseUrl={baseUrl} />
<main className="explorer-index-page grid grid-cols-12-full-width">
<header className="explorer-index-page__header grid grid-cols-12-full-width span-cols-14">
<h1 className="h1-semibold span-cols-12 col-start-2 collection-title">
Data Explorers
</h1>
<p className="span-cols-8 col-start-2 span-md-cols-12 col-md-start-2 body-2-regular collection-explanation">
Our data explorers gather many indicators together
to provide comprehensive overviews of their topics.
</p>
</header>
<ul className="explorer-index-page-list span-cols-12 col-start-2 grid grid-cols-4 grid-md-cols-2 grid-sm-cols-1">
{explorers.map((explorer) => (
<li key={explorer.slug}>
<a
className="explorer-index-page__card"
href={`${baseUrl}/${EXPLORERS_ROUTE_FOLDER}/${explorer.slug}`}
>
<img
width="850"
height="600"
loading="lazy"
src={`${EXPLORER_DYNAMIC_THUMBNAIL_URL}/${explorer.slug}.png`}
/>
<h2>{explorer.title}</h2>
<p>{explorer.subtitle}</p>
</a>
</li>
))}
</ul>
<ExplorerIndex baseUrl={baseUrl} explorers={explorers} />
</main>
<SiteFooter baseUrl={baseUrl} />
<SiteFooter
baseUrl={baseUrl}
context={SiteFooterContext.explorerIndexPage}
/>
<script dangerouslySetInnerHTML={{ __html: inlineJs }} />
</body>
</Html>
)
Expand Down
4 changes: 4 additions & 0 deletions site/runSiteFooterScripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
import { runAllGraphersLoadedListener } from "./runAllGraphersLoadedListener.js"
import { hydrateMultiDimDataPageContent } from "./multiDim/MultiDimDataPageContent.js"
import { hydrateDataCatalogPage } from "./DataCatalog/DataCatalog.js"
import { hydrateExplorerIndex } from "./ExplorerIndex.js"

export const runSiteFooterScripts = (
args:
Expand Down Expand Up @@ -66,6 +67,9 @@ export const runSiteFooterScripts = (
runCookiePreferencesManager()
void runDetailsOnDemand()
break
case SiteFooterContext.explorerIndexPage:
hydrateExplorerIndex()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, you need a bunch more here: Definitely runSiteNavigation, runCookiePreferencesManager, maybe also runSiteTools.

break
case SiteFooterContext.gdocsDocument:
hydrateOwidGdoc(debug, isPreviewing)
runAllGraphersLoadedListener()
Expand Down