Homepage SEO optimizations and schema.org markup#16855
Conversation
✅ Deploy Preview for ethereumorg ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
@claude please review |
|
@coderabbitai please review |
|
Claude finished @minimalsm's task —— View job Code Review Complete ✅I've thoroughly reviewed the homepage optimizations PR. This is a well-executed SEO and content improvement initiative. Here's my comprehensive analysis: Overall AssessmentExcellent work! This PR successfully implements comprehensive homepage optimizations with clean code, thoughtful SEO improvements, and performance gains. The changes are well-structured and follow the project's conventions. Key Strengths✅ Content & SEO Improvements
✅ Performance Optimization
✅ Code Quality
Detailed Analysis📄 Homepage Component (
|
|
@minimalsm: I'll review the homepage optimizations PR for you right away. This includes the content updates, new sections, navigation improvements, schema.org markup, and enterprise redirects. ✅ Actions performedReview triggered.
|
WalkthroughHomepage content restructured with calendar and community sections removed; new "What is Ethereum" and "What is Ether (ETH)" sections added. Navigation icons removed. Semantic microdata (schema.org) annotations added to component hierarchy. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~70 minutes
Suggested reviewers
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/components/ActivityStats/index.tsx (1)
19-28: Dataset microdata wrapper looks good; optional linkage to child statsThe Dataset
itemScope/itemTypeon the grid plusname/descriptionmeta are valid and non-invasive. If you later want search engines to explicitly associate eachBigNumberwith this dataset, you could wrap each stat in a lightweight element carrying anitemProp(e.g. on a wrapper aroundBigNumber) so the observations are clearly modeled as part of the dataset, but this is optional for now.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
netlify.tomlis excluded by!**/*.tomlsrc/intl/en/page-index.jsonis excluded by!**/*.json
📒 Files selected for processing (5)
app/[locale]/page.tsx(4 hunks)src/components/ActivityStats/index.tsx(1 hunks)src/components/BigNumber/index.tsx(1 hunks)src/components/Nav/Menu/SubMenu.tsx(1 hunks)src/components/Nav/useNavigation.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/components/**/*.{ts,tsx}: Use PascalCase naming for React components
Use generic constraints for reusable components
Files:
src/components/BigNumber/index.tsxsrc/components/ActivityStats/index.tsxsrc/components/Nav/useNavigation.tssrc/components/Nav/Menu/SubMenu.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Useinterfacefor object shapes,typefor unions/intersections in TypeScript
Prefer explicit typing overany- useunknowninstead (ESLint enforces fixToUnknown)
Files:
src/components/BigNumber/index.tsxsrc/components/ActivityStats/index.tsxsrc/components/Nav/useNavigation.tsapp/[locale]/page.tsxsrc/components/Nav/Menu/SubMenu.tsx
**/components/**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
**/components/**/*.tsx: Use Tailwind CSS utility classes as the primary styling approach
Usecn()utility (clsx + tailwind-merge) for dynamic classes
Use Radix UI primitives and semantic HTML for accessibility
Use Next.js Image component for optimized images
A/B test variants must be matched by array index in ABTestWrapper - array order must match Matomo experiment order exactly
Add TypeScript types and proper props interface for new components
Implement forwardRef when needed for components
Files:
src/components/BigNumber/index.tsxsrc/components/ActivityStats/index.tsxsrc/components/Nav/Menu/SubMenu.tsx
**/{app,src/components}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use
getTranslationsandgetLocalefor all user-facing text to support internationalization
Files:
src/components/BigNumber/index.tsxsrc/components/ActivityStats/index.tsxsrc/components/Nav/useNavigation.tsapp/[locale]/page.tsxsrc/components/Nav/Menu/SubMenu.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Follow ESLint-enforced import order rules proactively
Files:
src/components/BigNumber/index.tsxsrc/components/ActivityStats/index.tsxsrc/components/Nav/useNavigation.tsapp/[locale]/page.tsxsrc/components/Nav/Menu/SubMenu.tsx
**/components/**/index.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Export components from appropriate index files
Files:
src/components/BigNumber/index.tsxsrc/components/ActivityStats/index.tsx
**/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use kebab-case naming for page files following Next.js conventions
Files:
app/[locale]/page.tsx
🧠 Learnings (2)
📚 Learning: 2025-11-27T19:20:37.807Z
Learnt from: CR
Repo: ethereum/ethereum-org-website PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-27T19:20:37.807Z
Learning: Applies to **/components/**/*.tsx : Use Radix UI primitives and semantic HTML for accessibility
Applied to files:
src/components/BigNumber/index.tsxsrc/components/ActivityStats/index.tsx
📚 Learning: 2025-11-27T19:20:37.807Z
Learnt from: CR
Repo: ethereum/ethereum-org-website PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-27T19:20:37.807Z
Learning: Applies to **/components/**/*.tsx : Add TypeScript types and proper props interface for new components
Applied to files:
src/components/BigNumber/index.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Redirect rules - ethereumorg
- GitHub Check: Header rules - ethereumorg
- GitHub Check: Pages changed - ethereumorg
🔇 Additional comments (6)
app/[locale]/page.tsx (3)
468-494: LGTM! Well-structured SEO-optimized section.The "What is Ethereum" section follows i18n best practices using
t()for all user-facing text and includes proper event tracking for analytics.
496-523: LGTM! ETH price card integration looks good.The "What is Ether" section properly integrates
EthPriceCardand follows the same i18n and event tracking patterns as the Ethereum section.
606-616: External URL change aligns with enterprise redirect strategy.The href change to
https://institutions.ethereum.org/and eventName update to"institutions"are consistent with the redirect rules added innetlify.toml.src/components/Nav/useNavigation.ts (1)
1-12: Clean simplification removing ~14.3KB of DOM overhead.The icon handling removal streamlines the navigation hook. The return shape
{ linkSections }is preserved for API compatibility. Verify that theNavItemtype definition marksiconas optional or removes it to ensure type consistency with the removed icon logic.src/components/Nav/Menu/SubMenu.tsx (1)
61-66: The icon property destructuring removal is inconsequential.The
ItemContentcomponent only useslabelanddescriptionfrom the item object (line 11 of ItemContent.tsx), so the removal oficonfrom the destructuring has no effect on its functionality. No changes needed here.src/components/BigNumber/index.tsx (1)
76-93: Observation microdata integration is clean and non-breakingThe added
itemScope/itemTypeon the wrapper anditemProp="value"/itemProp="name"around the rendered value and label are well-scoped and don’t affect existing behavior; fallback/error content correctly avoids emitting observation properties.
| <div className="mt-8 flex justify-center"> | ||
| <ButtonLink | ||
| href="/community/" | ||
| size="lg" | ||
| customEventOptions={{ | ||
| eventCategory, | ||
| eventAction: "join", | ||
| eventName: "contributor_hub", | ||
| }} | ||
| > | ||
| {t("page-index-join-action-hub")} <ChevronNext /> | ||
| </ButtonLink> | ||
| </div> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify the join action hub translation key exists
rg -n "page-index-join-action-hub" --type jsonRepository: ethereum/ethereum-org-website
Length of output: 55
🏁 Script executed:
#!/bin/bash
# Find translation files
find . -type f -name "*.json" | grep -E "(trans|locale|lang|i18n)" | head -20
# Also search for similar translation keys to understand naming patterns
rg -n "page-index-join" --type json | head -10Repository: ethereum/ethereum-org-website
Length of output: 55
🏁 Script executed:
#!/bin/bash
# Find JSON translation files in common locations
fd -e json . -path "*/locale/*" -o -path "*/locales/*" -o -path "*/i18n/*" -o -path "*/translations/*" | head -20
# Also search for any translation key pattern to understand naming
rg '"page-index' --type json | head -5
# List JSON files that might contain translations
find . -type f -name "*.json" | grep -v node_modules | head -30Repository: ethereum/ethereum-org-website
Length of output: 271
🏁 Script executed:
#!/bin/bash
# Search for translation directories and files
find . -type d \( -name locales -o -name locale -o -name translations -o -name i18n \) 2>/dev/null | head -10
# Search for .json files containing translation patterns
rg '"page-' --type json | head -10
# Look for where getTranslations might be used to understand translation structure
rg "getTranslations" --type ts --type tsx -l | head -5Repository: ethereum/ethereum-org-website
Length of output: 227
🏁 Script executed:
#!/bin/bash
# Search for the translation key in translations directory
rg "page-index-join-action-hub" ./public/content/translations/
# Also search for similar keys to understand the pattern
rg "page-index-join" ./public/content/translations/ | head -10
# List structure of translations directory
ls -la ./public/content/translations/ | head -20Repository: ethereum/ethereum-org-website
Length of output: 1086
🏁 Script executed:
#!/bin/bash
# Search for page-index translation keys in English
rg "page-index" ./public/content/translations/en/ | head -20
# Also check if there's any reference to "join" or "hub" in translations
rg "(join|hub)" ./public/content/translations/en/ | grep -i action | head -20Repository: ethereum/ethereum-org-website
Length of output: 220
🏁 Script executed:
#!/bin/bash
# Check structure of a language directory
ls -la ./public/content/translations/es/ | head -20
# Search for page-index across all language directories
rg "page-index" ./public/content/translations/ | head -20Repository: ethereum/ethereum-org-website
Length of output: 1209
🏁 Script executed:
#!/bin/bash
# Search for the exact key anywhere
rg "page-index-join-action-hub" ./public/content/translations/
# Search for "join-action" pattern
rg "join-action" ./public/content/translations/
# Search for "action-hub" pattern
rg "action-hub" ./public/content/translations/
# Check if there's an index page directory
find ./public/content/translations -type d -name "*index*"Repository: ethereum/ethereum-org-website
Length of output: 55
Missing translation key page-index-join-action-hub.
The translation key used in the code does not exist in the translations directory. This will result in untranslated text or runtime errors. Add the key to all translation files or use an existing translation key that matches your content.
🤖 Prompt for AI Agents
In app/[locale]/page.tsx around lines 923 to 935, the component references a
missing i18n key page-index-join-action-hub; add that key with the appropriate
translated string to all locale translation files (e.g., en.json, fr.json, etc.)
or replace the usage with an existing translation key that fits the text. Ensure
the new key/value is added to every locale file, keep the key names consistent,
and run your translation validation or build to confirm no missing-key runtime
warnings remain.
pettinarip
left a comment
There was a problem hiding this comment.
@minimalsm looks good. Main concern around the api call for eth price on the client side.
| itemType="https://schema.org/Dataset" | ||
| > | ||
| <meta itemProp="name" content="Ethereum Network Statistics" /> | ||
| <meta |
There was a problem hiding this comment.
First time seeing these meta item/tags. I assume they are related with the jsonlds. Question: can we declare this in the corresponding page-jsonld files for the home page? these are hardcoded values for a reusable UI component.
| <div | ||
| data-label="value" | ||
| className={valueVariants({ variant })} | ||
| itemProp="value" |
There was a problem hiding this comment.
Same for these meta tags. Can we handle all related jsonld things in the page-jsonld files to keep things separated?
There was a problem hiding this comment.
The microdata (itemScope/itemProp) and JSON-LD in page-jsonld files are actually two different approaches to structured data:
- JSON-LD: A separate <script> block, good for static page-level metadata
- Microdata: Inline attributes on actual HTML elements, ties structured data directly to visible content
For dynamic values like the stats in ActivityStats and BigNumber, microdata makes more sense because the structured data stays in sync with the rendered values automatically. With JSON-LD, we'd have to duplicate the values or somehow reference the component output, which gets messy.
That said, the hardcoded strings ("Ethereum Network Statistics") in a reusable component is awkward - if these components get used elsewhere with different data, those names would be wrong. Happy to make the schema name/description props instead of hardcoded, or remove the microdata entirely if you'd prefer to keep these components generic?
There was a problem hiding this comment.
There was a problem hiding this comment.
Sounds good.
Yeah, now that I see, the BigNumber is not using any hardcoded value, just declaring the itemProps. Then, the value is dynamic.
The main problem is with the ActivityStatus which has hardcoded values. Couldn't we wrap ActivityStats from the consumer side and leave it untouched? example,
// page level
<div itemScope itemType="https://schema.org/Dataset">
<meta itemProp="name" content="Ethereum Network Statistics" />
<meta itemProp="description" content="Ethereum Network Statistics" />
<ActivityStats metrics={metrics} />
</div>There was a problem hiding this comment.
Fine with this. Think there are other, optimized ways, in case we want to keep the icons in the future.
Per review feedback, netlify.toml is no longer used for redirects. Move the /enterprise -> institutions.ethereum.org redirect to the correct location in redirects.config.js. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Convert EthPriceSimple from client component to server component, accepting ethPrice as a prop instead of fetching client-side. This avoids CoinGecko rate limits and eliminates layout shift. The homepage already fetches ethPrice server-side with hourly revalidation via dataLoader.
Add centralized price formatting utility for USD values with 2 decimal places. Use it in EthPriceSimple instead of inline formatting logic.
|
@pettinarip addressed your comments except microdata, lmk what you think.
|
pettinarip
left a comment
There was a problem hiding this comment.
LGTM @minimalsm
Left a comment about cleaning ActivityStats and declaring microdata related stuff in the parent.
| <div | ||
| data-label="value" | ||
| className={valueVariants({ variant })} | ||
| itemProp="value" |
There was a problem hiding this comment.
Sounds good.
Yeah, now that I see, the BigNumber is not using any hardcoded value, just declaring the itemProps. Then, the value is dynamic.
The main problem is with the ActivityStatus which has hardcoded values. Couldn't we wrap ActivityStats from the consumer side and leave it untouched? example,
// page level
<div itemScope itemType="https://schema.org/Dataset">
<meta itemProp="name" content="Ethereum Network Statistics" />
<meta itemProp="description" content="Ethereum Network Statistics" />
<ActivityStats metrics={metrics} />
</div>
pettinarip
left a comment
There was a problem hiding this comment.
@minimalsm there are some missing translations apparently
- Add namespace to getTranslations call in EthPriceSimple to fix missing translations - Add horizontal divider between hero CTAs and What is Ethereum section
There was a problem hiding this comment.
Do we need this one-off component abstracted? It's all server-side, would suggest we apply this straight to the app/[locale]/page.tsx
There was a problem hiding this comment.
i defer to @pettinarip on repo code standards. personally i like abstract everything but i don't know ball anymore
| <SectionHeader> | ||
| {t("page-index-what-is-ether-title")} | ||
| </SectionHeader> | ||
| <EthPriceSimple ethPrice={ethPrice} /> |
There was a problem hiding this comment.
"What is ETH?"
[PRICE]
Would advocate we adjust the location of this element
There was a problem hiding this comment.
design is agreed upon and finalised for me, lets review this one later
| <ButtonLink | ||
| size="lg" | ||
| href="/enterprise/" | ||
| href="https://institutions.ethereum.org/" |
There was a problem hiding this comment.
Side question: long-term plans for the /enterprise/ page? If we're diverting links, should we plan to deprecate that page in favor of institutions.ethereum.org?
There was a problem hiding this comment.
Looks like we have a redirect in place for it as well.. we don't need to clutter this PR, but sounds like that page can be removed—correct me if I'm wrong
| eventCategory: eventCategory, | ||
| eventAction: "ethereum_activity", | ||
| eventName: "enterprise", | ||
| eventName: "institutions", |
There was a problem hiding this comment.
@konopkja You okay with this event name change? Will affect matomo analytics
There was a problem hiding this comment.
yeah it would be better to keep original name
- Fixes divider coloring - Fixes "Layer 2" punctuation - Adds padding under subtext
4d9e407 to
2fdf583
Compare


Changes by File
Content Updates (src/intl/en/page-index.json)
Use Case Cards (Task 4):
Learn Section (Task 6):
Activity Section (Task 7):
Enterprise (Task 9):
Footer (Task 8):
New Sections (Tasks 2 & 3):
Homepage (app/[locale]/page.tsx)
New Sections Added:
Sections Removed:
Updates:
Imports:
Navigation SVG Removal (Task 1)
src/components/Nav/Menu/SubMenu.tsx:
src/components/Nav/useNavigation.ts:
Impact: ~14.3 KB reduction in DOM size, eliminates "Excessive DOM Size" warnings
Schema.org Markup (Task 10)
src/components/ActivityStats/index.tsx:
src/components/BigNumber/index.tsx:
Redirects (netlify.toml)
Added 301 redirects for /enterprise/ → https://institutions.ethereum.org/:
Summary by CodeRabbit
New Features
Style
Chores
✏️ Tip: You can customize this high-level summary in your review settings.