Skip to content

refactor(resources): refine page design to Figma spec #15164

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

Merged
4 changes: 2 additions & 2 deletions src/intl/en/page-resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,12 @@
"page-resources-hero-title": "Resources",
"page-resources-hero-header": "Ethereum Dashboards",
"page-resources-hero-description": "Discover a list of community-curated resources to stay updated on all major Ethereum ecosystem developments.",
"page-resources-find-more": "Find more great resources on <a href=\"https://ethereumdashboards.com\" target=\"_blank\">ethereumdashboards.com</a>",
"page-resources-find-more": "Find more great resources on",
"page-resources-contribute-title": "Contribute",
"page-resources-contribute-description": "This dashboard is a living page that requires frequent updates. Help find the best resources to give an overview of the Ethereum ecosystem.",
"page-resources-suggest-resource": "Suggest a resource",
"page-resources-found-bug": "Found a bug",
"page-resources-whats-on-this-page": "What's on this page",
"page-resources-banner-notification-message": "Resources dashboard is new!",
"page-resources-share-feedback": "Please share your feedback with us"
}
}
7 changes: 7 additions & 0 deletions src/pages/[locale]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,13 @@ const HomePage = ({
href="/resources/"
isSecondary
variant="outline"
onClick={() =>
trackCustomEvent({
eventCategory,
eventAction: "ethereum_activity",
eventName: "ethereum_activity",
})
}
>
{t("page-index:page-index-activity-action")} <ChevronNext />
</ButtonLink>
Expand Down
252 changes: 153 additions & 99 deletions src/pages/[locale]/resources.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ import { ResourceItem, ResourcesContainer } from "@/components/Resources"
import { useResources } from "@/components/Resources/useResources"
import Translation from "@/components/Translation"
import { ButtonLink } from "@/components/ui/buttons/Button"
import { Stack, VStack } from "@/components/ui/flex"
import Link from "@/components/ui/Link"
import { Section } from "@/components/ui/section"

import { cn } from "@/lib/utils/cn"
import { dataLoader } from "@/lib/utils/data/dataLoader"
import { existsNamespace } from "@/lib/utils/existsNamespace"
import { getLastDeployDate } from "@/lib/utils/getLastDeployDate"
import { trackCustomEvent } from "@/lib/utils/matomo"
import { getLocaleTimestamp } from "@/lib/utils/time"
import { getRequiredNamespacesForPage } from "@/lib/utils/translations"

Expand All @@ -36,6 +38,8 @@ import loadNamespaces from "@/i18n/loadNamespaces"
import { fetchGrowThePie } from "@/lib/api/fetchGrowThePie"
import heroImg from "@/public/images/heroes/guides-hub-hero.jpg"

const EVENT_CATEGORY = "dashboard"

// In seconds
const REVALIDATE_TIME = BASE_TIME_UNIT * 1

Expand Down Expand Up @@ -103,6 +107,13 @@ const ResourcesPage = ({ txCostsMedianUsd }) => {
GITHUB_REPO_URL
).toString()}
className="visited:text-white"
onClick={() => {
trackCustomEvent({
eventCategory: EVENT_CATEGORY,
eventAction: "links",
eventName: "Ethereum.org Github Page Feedback",
})
}}
>
{t("page-resources-share-feedback")}
</Link>
Expand All @@ -114,112 +125,155 @@ const ResourcesPage = ({ txCostsMedianUsd }) => {
description={t("page-resources-hero-description")}
heroImg={heroImg}
/>

<div className="sticky top-1 my-8 flex flex-col items-center gap-3 py-4 text-center md:top-6 md:px-2">
<div className="my-2 text-body-medium">
{t("page-resources-whats-on-this-page")}
</div>
<nav className="z-sticky mx-4 flex max-w-full gap-1 overflow-x-auto bg-background p-2 shadow md:max-w-[calc(100%-2rem)] md:rounded-2xl md:border md:p-0.5 md:shadow-lg">
{resourceSections.map(({ key, title, icon }) => (
<ButtonLink
key={key}
href={`#${key}`}
variant="ghost"
isSecondary
className={cn(
"relative text-nowrap rounded-xl px-4 py-2 text-sm [&_svg]:shrink-0 [&_svg]:text-sm",
activeSection === key && "!text-primary"
)}
>
{activeSection === key && (
<motion.div
layoutId="active-section-highlight"
className="absolute inset-0 z-0 rounded-xl bg-primary-low-contrast"
/>
)}
{icon && <span className="z-10 text-lg">{icon}</span>}
<span className="relative z-10">{title}</span>
</ButtonLink>
))}
</nav>
</div>

{resourceSections.map(({ key, icon, title: sectionTitle, boxes }) => (
<section id={key} key={key} className="mb-16 scroll-mt-40">
<div className="group flex w-full items-center gap-3 border-b bg-transparent px-4 py-6">
<div className="grid size-12 place-items-center rounded-lg border border-border-low-contrast text-2xl [&_svg]:shrink-0">
{icon || <StackIcon />}
</div>
<h2 className="flex-1 text-start font-black">{sectionTitle}</h2>
<Stack className="gap-4 px-2 py-6 md:gap-8 md:px-4 lg:px-8 xl:gap-11">
<div className="sticky top-5 flex flex-col items-center gap-3 text-center md:top-6 md:px-2">
<div className="my-2 text-body-medium">
{t("page-resources-whats-on-this-page")}
</div>
<div className="grid grid-cols-1 gap-8 px-4 pb-12 pt-8 md:pb-12 md:pt-8 lg:grid-cols-2">
{boxes.map(({ title, metric, items, className }) => (
<div
<nav className="z-sticky mx-4 flex max-w-full gap-1 overflow-x-auto bg-background p-2 shadow md:max-w-[calc(100%-2rem)] md:rounded-2xl md:border md:p-0.5 md:shadow-lg">
{resourceSections.map(({ key, title, icon }) => (
<ButtonLink
key={key}
href={`#${key}`}
variant="ghost"
isSecondary
className={cn(
"overflow-hidden rounded-2xl border shadow-lg",
className
"relative text-nowrap rounded-xl px-4 py-2 text-sm [&_svg]:shrink-0 [&_svg]:text-sm",
activeSection === key && "!text-primary"
)}
key={title}
onClick={() =>
trackCustomEvent({
eventCategory: EVENT_CATEGORY,
eventAction: "whats_on_this_page",
eventName:
"network,using, scaling, resilience, privacy_security",
})
}
>
<div className="border-b bg-[#ffffff] px-6 py-4 font-bold dark:bg-[#171717]">
{title}
{activeSection === key && (
<motion.div
layoutId="active-section-highlight"
className="absolute inset-0 z-0 rounded-xl bg-primary-low-contrast"
/>
)}
{icon && <span className="z-10 text-lg">{icon}</span>}
<span className="relative z-10">{title}</span>
</ButtonLink>
))}
</nav>
</div>
<Stack className="gap-11 pt-12 md:gap-16 lg:gap-24">
{resourceSections.map(({ key, icon, title: sectionTitle, boxes }) => (
<Stack key={key} asChild>
<section id={key} className="scroll-mt-40 gap-8 md:gap-6">
<div className="group flex w-full items-center gap-4 border-b bg-transparent px-2 py-4">
<div className="grid size-12 place-items-center rounded-lg border border-border-low-contrast text-2xl [&_svg]:shrink-0">
{icon || <StackIcon />}
</div>
<h2 className="flex-1 text-start font-black">
{sectionTitle}
</h2>
</div>
<div className="h-full bg-background bg-gradient-to-br from-white to-primary/10 px-2 py-6 dark:from-transparent dark:to-primary/10">
{metric && metric}
<ResourcesContainer>
{items.map((item) => (
<ResourceItem item={item} key={item.title} />
))}
</ResourcesContainer>
<div className="grid grid-cols-1 gap-8 lg:grid-cols-2 lg:gap-y-6">
{boxes.map(({ title, metric, items, className }) => (
<div
className={cn(
"overflow-hidden rounded-2xl border shadow-lg",
className
)}
key={title}
>
<div className="border-b bg-[#ffffff] px-6 py-4 font-bold dark:bg-[#171717]">
{title}
</div>
<div className="h-full bg-background bg-gradient-to-br from-white to-primary/10 px-2 py-6 dark:from-transparent dark:to-primary/10">
{metric && metric}
<ResourcesContainer>
{items.map((item) => (
<ResourceItem item={item} key={item.title} />
))}
</ResourcesContainer>
</div>
</div>
))}
</div>
</div>
))}
</div>
</section>
))}

<div className="mb-20 text-center">
<Translation id="page-resources:page-resources-find-more" />
</div>

<Section
id="contribute"
className={cn(
"before:absolute before:-inset-px before:bottom-0 before:z-hide before:rounded-[calc(theme(borderRadius.4xl)+1px)] before:content-['']", // Border/gradient positioning
"before:bg-gradient-to-b before:from-primary-hover/[0.24] before:to-primary-hover/[0.08] before:dark:from-primary-hover/40 before:dark:to-primary-hover/20", // Border/gradient coloring
"relative inset-0 rounded-4xl bg-background" // Paint background color over card portion
)}
>
<div className="mb-12 flex flex-col gap-y-8 rounded-4xl bg-radial-a px-8 py-12 lg:mb-32 xl:mb-36">
<div className="flex flex-col gap-y-4 text-center">
<h2>{t("page-resources-contribute-title")}</h2>
<p>{t("page-resources-contribute-description")}</p>
</div>
<div className="mx-auto grid grid-cols-1 gap-16 md:grid-cols-2">
{/* TODO: Add issue template for resource listing and redirect to new template */}
<ButtonLink
href={new URL(
"issues/new?template=feature_request.yaml",
GITHUB_REPO_URL
).toString()}
variant="outline"
isSecondary
>
{t("page-resources-suggest-resource")}
</ButtonLink>
<ButtonLink
href={new URL(
"issues/new?template=bug_report.yaml",
GITHUB_REPO_URL
).toString()}
variant="outline"
isSecondary
>
<FaGithub /> {t("page-resources-found-bug")}
</ButtonLink>
</section>
</Stack>
))}
</Stack>

<VStack className="gap-4 py-16">
<div className="text-center font-bold">
<Translation id="page-resources:page-resources-find-more" />
</div>
</div>
</Section>
<ButtonLink
href="https://ethereumdashboards.com"
size="lg"
onClick={() => {
trackCustomEvent({
eventCategory: EVENT_CATEGORY,
eventAction: "links",
eventName: "ethereumdashboards.com",
})
}}
>
ethereumdashboards.com
</ButtonLink>
</VStack>
Copy link
Member

Choose a reason for hiding this comment

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

This get's a little complicated with translations, since not languages structures sentences the same as english. That was why the link was nested in the json string, so then translators can the move the link where it fits best within the sentence.

@lukassim Any thoughts if we could get away with this type of trailing button label in regards to translations?

image

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah good point ideally no links are in a fixed position in regards to the text since sentence structures can be different, this would likely cause issues in some languages

Copy link
Contributor Author

@TylerAPfledderer TylerAPfledderer Mar 28, 2025

Choose a reason for hiding this comment

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

@wackerow @lukassim

If ya don't mind 😅 what about keeping the text as a statement that's separate from the link?

"Find more great resources!"

<Button />

So, not limit the flexibility of the design, while still being clear of the action. When we have other links that take action on the page that look like buttons, if we kept it as a link here, it might look like there is a broken style.

There is nothing else near this collection in the whitespace, so the clarity should still be maintained.


<Section
id="contribute"
className="relative rounded-4xl border border-body/5 bg-background"
>
<VStack className="rounded-4xl bg-radial-a px-4 py-6 md:py-12">
<Stack className="max-w-xl gap-y-10 py-6 lg:max-w-[700px]">
<div className="flex flex-col gap-y-4 text-center">
<h2>{t("page-resources-contribute-title")}</h2>
<p className="text-lg">
{t("page-resources-contribute-description")}
</p>
</div>
<div className="mx-auto grid grid-cols-1 gap-x-3 gap-y-4 md:grid-cols-2">
{/* TODO: Add issue template for resource listing and redirect to new template */}
<ButtonLink
href={new URL(
"issues/new?template=feature_request.yaml",
GITHUB_REPO_URL
).toString()}
variant="outline"
isSecondary
onClick={() => {
trackCustomEvent({
eventCategory: EVENT_CATEGORY,
eventAction: "links",
eventName: "Ethereum.org Github Feature Request",
})
}}
>
{t("page-resources-suggest-resource")}
</ButtonLink>
<ButtonLink
href={new URL(
"issues/new?template=bug_report.yaml",
GITHUB_REPO_URL
).toString()}
variant="outline"
isSecondary
onClick={() => {
trackCustomEvent({
eventCategory: EVENT_CATEGORY,
eventAction: "links",
eventName: "Ethereum.org Github Bug Report",
})
}}
>
<FaGithub /> {t("page-resources-found-bug")}
</ButtonLink>
</div>
</Stack>
</VStack>
</Section>
</Stack>
</MainArticle>
)
}
Expand Down