diff --git a/.all-contributorsrc b/.all-contributorsrc index fe7324d575d..0a382248673 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -937,7 +937,8 @@ "profile": "https://github.com/EmanHerawy", "contributions": [ "translation", - "code" + "code", + "ideas" ] }, { @@ -4639,7 +4640,8 @@ "avatar_url": "https://avatars.githubusercontent.com/u/55439064?v=4", "profile": "https://github.com/raj-shekhar1", "contributions": [ - "doc" + "doc", + "ideas" ] }, { @@ -5547,7 +5549,8 @@ "avatar_url": "https://avatars.githubusercontent.com/u/735288?v=4", "profile": "http://www.sigasi.com", "contributions": [ - "doc" + "doc", + "code" ] }, { @@ -6828,7 +6831,8 @@ "avatar_url": "https://avatars.githubusercontent.com/u/14298799?v=4", "profile": "https://github.com/smartcontracts", "contributions": [ - "doc" + "doc", + "bug" ] }, { @@ -7916,6 +7920,228 @@ "contributions": [ "doc" ] + }, + { + "login": "hakuta", + "name": "hakuta", + "avatar_url": "https://avatars.githubusercontent.com/u/806605?v=4", + "profile": "https://github.com/hakuta", + "contributions": [ + "doc" + ] + }, + { + "login": "MiloBowman", + "name": "MiloBowman", + "avatar_url": "https://avatars.githubusercontent.com/u/104447804?v=4", + "profile": "https://github.com/MiloBowman", + "contributions": [ + "doc" + ] + }, + { + "login": "tadeodao", + "name": "tadeo", + "avatar_url": "https://avatars.githubusercontent.com/u/94108039?v=4", + "profile": "https://github.com/tadeodao", + "contributions": [ + "doc" + ] + }, + { + "login": "creacodigos", + "name": "Jorge Santana", + "avatar_url": "https://avatars.githubusercontent.com/u/50615503?v=4", + "profile": "http://creacodigos.com", + "contributions": [ + "content" + ] + }, + { + "login": "rolodexter", + "name": "rolodexter", + "avatar_url": "https://avatars.githubusercontent.com/u/977925?v=4", + "profile": "http://www.rolodexter1.com", + "contributions": [ + "doc" + ] + }, + { + "login": "RanchHowards", + "name": "RanchHowards", + "avatar_url": "https://avatars.githubusercontent.com/u/69303624?v=4", + "profile": "https://github.com/RanchHowards", + "contributions": [ + "doc", + "bug" + ] + }, + { + "login": "didoshotev", + "name": "Deyan Shotev", + "avatar_url": "https://avatars.githubusercontent.com/u/62618421?v=4", + "profile": "https://github.com/didoshotev", + "contributions": [ + "code" + ] + }, + { + "login": "PraneshASP", + "name": "Pranesh A S", + "avatar_url": "https://avatars.githubusercontent.com/u/42379522?v=4", + "profile": "https://github.com/PraneshASP", + "contributions": [ + "doc", + "bug" + ] + }, + { + "login": "shir22", + "name": "shir22", + "avatar_url": "https://avatars.githubusercontent.com/u/33841818?v=4", + "profile": "https://github.com/shir22", + "contributions": [ + "doc", + "bug" + ] + }, + { + "login": "nikashitsa", + "name": "Nikita Verkhovin", + "avatar_url": "https://avatars.githubusercontent.com/u/1029908?v=4", + "profile": "https://github.com/nikashitsa", + "contributions": [ + "bug" + ] + }, + { + "login": "pushkar2112", + "name": "Pushkar Verma", + "avatar_url": "https://avatars.githubusercontent.com/u/50198312?v=4", + "profile": "https://pushkarverma.dev", + "contributions": [ + "doc", + "ideas" + ] + }, + { + "login": "vincentweisser", + "name": "Vincent Weisser", + "avatar_url": "https://avatars.githubusercontent.com/u/32839303?v=4", + "profile": "http://vincentweisser.com", + "contributions": [ + "doc" + ] + }, + { + "login": "koogawa", + "name": "Kosuke Ogawa", + "avatar_url": "https://avatars.githubusercontent.com/u/893643?v=4", + "profile": "http://www.koogawa.com", + "contributions": [ + "doc", + "bug" + ] + }, + { + "login": "Feerol", + "name": "Fatih Eren Erol", + "avatar_url": "https://avatars.githubusercontent.com/u/47645405?v=4", + "profile": "https://github.com/Feerol", + "contributions": [ + "doc" + ] + }, + { + "login": "olalonde", + "name": "Oli Lalonde", + "avatar_url": "https://avatars.githubusercontent.com/u/416585?v=4", + "profile": "https://syskall.com", + "contributions": [ + "doc" + ] + }, + { + "login": "gingerheart86", + "name": "gingerheart86", + "avatar_url": "https://avatars.githubusercontent.com/u/100948227?v=4", + "profile": "https://github.com/gingerheart86", + "contributions": [ + "doc" + ] + }, + { + "login": "naveen106", + "name": "Naveen Kumar", + "avatar_url": "https://avatars.githubusercontent.com/u/61573478?v=4", + "profile": "https://github.com/naveen106", + "contributions": [ + "doc" + ] + }, + { + "login": "treethought", + "name": "Cam Sweeney", + "avatar_url": "https://avatars.githubusercontent.com/u/15894818?v=4", + "profile": "https://github.com/treethought", + "contributions": [ + "doc" + ] + }, + { + "login": "moyedx3", + "name": "moyed", + "avatar_url": "https://avatars.githubusercontent.com/u/108647630?v=4", + "profile": "https://github.com/moyedx3", + "contributions": [ + "doc" + ] + }, + { + "login": "shelleyolivia", + "name": "shelleyolivia", + "avatar_url": "https://avatars.githubusercontent.com/u/108895606?v=4", + "profile": "https://github.com/shelleyolivia", + "contributions": [ + "doc", + "ideas" + ] + }, + { + "login": "zyjblockchain", + "name": "Sandy", + "avatar_url": "https://avatars.githubusercontent.com/u/40423181?v=4", + "profile": "http://sandyzhou911@gmail.com", + "contributions": [ + "doc" + ] + }, + { + "login": "NachoRoizman", + "name": "NachoRoizman", + "avatar_url": "https://avatars.githubusercontent.com/u/107893772?v=4", + "profile": "https://github.com/NachoRoizman", + "contributions": [ + "doc" + ] + }, + { + "login": "M-Ivan", + "name": "Iván Miragaya", + "avatar_url": "https://avatars.githubusercontent.com/u/72365253?v=4", + "profile": "https://linkedin.com/in/miragaya-ivan", + "contributions": [ + "code" + ] + }, + { + "login": "smejak", + "name": "Jakub Smékal", + "avatar_url": "https://avatars.githubusercontent.com/u/20759274?v=4", + "profile": "https://github.com/smejak", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 7, diff --git a/.github/ISSUE_TEMPLATE/suggest_wallet.yaml b/.github/ISSUE_TEMPLATE/suggest_wallet.yaml index 95ead035b89..c8fea37b5ff 100644 --- a/.github/ISSUE_TEMPLATE/suggest_wallet.yaml +++ b/.github/ISSUE_TEMPLATE/suggest_wallet.yaml @@ -136,7 +136,7 @@ body: - type: input id: wallet_smart_contract_audit attributes: - label: Has the wallet's smart contract code been audited? + label: Has the wallet's smart contract code or security modules been audited? description: If yes, provide a link to any audits. - type: input id: wallet_security_team @@ -149,10 +149,10 @@ body: label: Any other security testing that should be noted? description: Please note any other security precautions taken. - type: textarea - id: wallet_spam_protection + id: wallet_scam_protection attributes: - label: Spam protection? - description: Does the wallet employ any practices to warn users against potential spam (e.g. when interacting with suspicious accounts/contracts)? + label: Scam protection? + description: Does the wallet employ any practices to warn users against potential scams (e.g. when interacting with suspicious accounts/contracts)? - type: markdown id: features attributes: @@ -209,6 +209,11 @@ body: attributes: label: Does the wallet support multi-chain networks? description: Please provide documentation on multi-chain networks this wallet supports. + - type: input + id: wallet_l2_support + attributes: + label: Does the wallet support Ethereum layer 2 networks? + description: Please provide documentation on Ethereum layer 2 networks this wallet supports. - type: input id: wallet_customize_gas_fees attributes: diff --git a/.gitignore b/.gitignore index 1ba1dd163e8..e8c50ec27f0 100644 --- a/.gitignore +++ b/.gitignore @@ -77,4 +77,7 @@ src/data/contributors.json # These files are generated by `yarn merge-translations` command src/intl/*.json # Auto generated code when gatsby build the site -src/gatsby-types.d.ts \ No newline at end of file +src/gatsby-types.d.ts + +# Exported Crowdin files +.crowdin diff --git a/README.md b/README.md index f17e8d7cf32..667db3428fc 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![Discord](https://img.shields.io/discord/714888181740339261?color=1C1CE1&label=ethereum.org%20%7C%20Discord%20%F0%9F%91%8B%20&style=flat-square)](https://discord.gg/CetY6Y4) [![Twitter Follow](https://img.shields.io/twitter/follow/ethdotorg.svg?style=social)](https://twitter.com/ethdotorg) [![Crowdin](https://badges.crowdin.net/ethereum-org/localized.svg)](https://crowdin.com/project/ethereum-org) +[![gitpoap badge](https://public-api.gitpoap.io/v1/repo/ethereum/ethereum-org-website/badge)](https://www.gitpoap.io/gh/ethereum/ethereum-org-website)
ethereum logo @@ -310,7 +311,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Jaroslav Macej

🌍 -
Eman Herawy

🌍 💻 +
Eman Herawy

🌍 💻 🤔
Bellinas

🌍
Alexander Cherkashin

🌍
Enoch Mbaebie

🌍 @@ -822,7 +823,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Gianni Alessandroni

📖 -
Raj Shekhar Bhardwaj

📖 +
Raj Shekhar Bhardwaj

📖 🤔
joakimengerstam

📖
Nikita Drozd

🐛 📖
Scott

🎨 🐛 @@ -948,7 +949,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Damian Schenkelman

📖 -
Hendrik Eeckhaut

📖 +
Hendrik Eeckhaut

📖 💻
Susannah Evans

📖
Minimalist Optimalist

🐛
vluna

💻 🐛 🖋 @@ -1123,7 +1124,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Oskar Mendel

💻
thewild-being

🤔
Mihrac Cerrahoglu

🤔 -
smartcontracts

📖 +
smartcontracts

📖 🐛
Samay Lakhani

📖
vdusart

📖 💻 @@ -1274,6 +1275,36 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
tree

📖
Stephen Fluin

📖 +
hakuta

📖 +
MiloBowman

📖 +
tadeo

📖 +
Jorge Santana

🖋 +
rolodexter

📖 + + +
RanchHowards

📖 🐛 +
Deyan Shotev

💻 +
Pranesh A S

📖 🐛 +
shir22

📖 🐛 +
Nikita Verkhovin

🐛 +
Pushkar Verma

📖 🤔 +
Vincent Weisser

📖 + + +
Kosuke Ogawa

📖 🐛 +
Fatih Eren Erol

📖 +
Oli Lalonde

📖 +
gingerheart86

📖 +
Naveen Kumar

📖 +
Cam Sweeney

📖 +
moyed

📖 + + +
shelleyolivia

📖 🤔 +
Sandy

📖 +
NachoRoizman

📖 +
Iván Miragaya

💻 +
Jakub Smékal

📖 diff --git a/docs/best-practices.md b/docs/best-practices.md index e5e397b491d..560704e6d70 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -52,7 +52,7 @@ Markdown will be translated as whole pages of content, so no specific action is - _tl;dr Each individual JSON entry should be a complete phrase by itself_ -- This is done using the `Translation` component. However there is an alternative method for regular JS: `gatsby-plugin-intl` with `/src/utils/translations.ts` +- This is done using the `Translation` component. However there is an alternative method for regular JS: `gatsby-theme-i18n` with `/src/utils/translations.ts` - **Method one: `` component (preferred if only needed in JSX)** @@ -66,7 +66,7 @@ Markdown will be translated as whole pages of content, so no specific action is - **Method two: `translateMessageId()`** ```tsx - import { useIntl } from "gatsby-plugin-intl" + import { useIntl } from "react-intl" import { translateMessageId } from "src/utils/translations" // Utilize anywhere in JS using diff --git a/docs/event-tracking.md b/docs/event-tracking.md new file mode 100644 index 00000000000..31ccf6fa53e --- /dev/null +++ b/docs/event-tracking.md @@ -0,0 +1,97 @@ +# Event tracking on ethereum.org + +This is a guide on how to prepare event tracking when creating a new page or redesigning an existing page. + +## What are events? + +Events are user interactions on the application that standard pageviews cannot track within a session. We create custom code snippets in the application in order to trigger these events. + +Events are useful for measuring user engagement on the website. Tracking events lets us know when users interact with elements and forms and can help us understand how successful users are at accomplishing their goals. + +Event tracking is a great way to validate our design decisions and assumptions. We can create reports in Matomo to gather insights and improve our product. + +[View the Matomo guide on event tracking](https://matomo.org/guide/reports/event-tracking/). + +## How is event tracking implemented? + +ethereum.org uses Matomo, an open-source alternative to Google Analytics, allowing us to protect user privacy by not sharing any analytics with third parties. + +We implemented Matomo using the [JavaScript tracking client](https://developer.matomo.org/guides/tracking-javascript-guide) via the [`gatsby-matomo-plugin`](https://github.com/kremalicious/gatsby-plugin-matomo) Gatsby plugin. + +## What to measure? + +Ideally, ask yourself what design decision/assumptions have been made on the page and should/could be validated by measured performance: + +- clicks +- downloads +- site searches +- popups viewed/dismissed +- form fields abandoned +- scroll behavior down a page + +This data can be later used to decide whether a feature is being used or is underperforming. + +It's helpful to ask yourself how the results of what we track and measure might influence our decision-making. For example, measuring something that won't help us make concrete product decisions is probably not worth tracking. + +# How to name events? + +Broadly, events should be grouped by specific topic (e.g. L2 page external links, selected bridge, selected cex). + +## Each event comprises of 4 hierarchical values: + +1. Category (other events may share the same category if one feature has several actions) +2. Action +3. Name (optional) +4. Value (optional, can be number or text) + +## Category + +Please consider the page's visual position when deciding which events should be grouped together (under the same category). Ideally, all events related to one feature should be grouped together under the same category only if there is also a single position on the page where the event can be triggered. If in doubt, always use a different category when a feature gets used in multiple places on the page. + +Example: +Find wallets page redirects to external links (wallets) in two positions: A) through the main list of wallets B) Through a modal window with detailed info about a specific wallet. In this case, we would like to have two separate categories for external links instead of one: + +- Matomo list view + - Category: WalletExternalLinkList + - Action: Go to wallet + - eventName: WalletName + - Value: position +- Matomo modal view + - Category: WalletExternalLinkModal + - Action: Go to wallet + - eventName: WalletName + - Value: position + +Such division allows us to identify where a user clicked on the page precisely; if all external links were under one category, "ExternalLink", we would not be able to measure the performance difference between the list and the modal window. + +## Usage + +Ethereum.org has a utility function (`trackCustomEvent`) for easily creating Matomo events. + +```javascript +import { trackCustomEvent } from "../utils/matomo" +``` + +The function requires an object of event options. See the example below. + +```javascript +const handleEvent = (): void => { + trackCustomEvent({ + eventCategory: `FeedbackWidget toggled`, + eventAction: `Clicked`, + eventName: `Opened feedback widget`, + eventValue: `1`, + }) +} +``` + +## Hidden gem of tracking: Value + +Can be used to get more info on the UX. + +Examples: + +- Use it to track the average position of clicked search result +- What terms are entered into the search field +- Which option is chosen from a dropdown menu +- How many or what filters are applied when filtering the list of wallets diff --git a/gatsby-browser.tsx b/gatsby-browser.tsx index 904ebb3e16f..1bbf32be586 100644 --- a/gatsby-browser.tsx +++ b/gatsby-browser.tsx @@ -5,7 +5,8 @@ */ import React from "react" -import Layout from "./src/components/Layout" +import browserLang from "browser-lang" +import { withPrefix, GatsbyBrowser } from "gatsby" import Prism from "prism-react-renderer/prism" ;(typeof global !== "undefined" ? global : window).Prism = Prism @@ -15,12 +16,52 @@ import "@formatjs/intl-locale/polyfill" import "@formatjs/intl-numberformat/polyfill" import "@formatjs/intl-numberformat/locale-data/en" +import Layout from "./src/components/Layout" +import { + supportedLanguages, + defaultLanguage, + isLang, +} from "./src/utils/languages" +import { Context } from "./src/types" + // Default languages included: // https://github.com/FormidableLabs/prism-react-renderer/blob/master/src/vendor/prism/includeLangs.js require("prismjs/components/prism-solidity") // Prevents from unmounting on page transitions // https://www.gatsbyjs.com/docs/layout-components/#how-to-prevent-layout-components-from-unmounting -export const wrapPageElement = ({ element, props }) => ( - {element} -) +export const wrapPageElement: GatsbyBrowser< + any, + Context +>["wrapPageElement"] = ({ element, props }) => { + const { location, pageContext } = props + const { pathname, search } = location + const { originalPath } = pageContext + + const [, pathLocale] = pathname.split("/") + + // client side redirect on paths that don't have a locale in them. Most useful + // on dev env where we don't have server redirects + if (!isLang(pathLocale)) { + let detected = + window.localStorage.getItem("eth-org-language") || + browserLang({ + languages: supportedLanguages, + fallback: defaultLanguage, + }) + + if (!isLang(detected)) { + detected = defaultLanguage + } + + const queryParams = search || "" + const newUrl = withPrefix(`/${detected}${originalPath}${queryParams}`) + window.localStorage.setItem("eth-org-language", detected) + window.location.replace(newUrl) + + // can't return null here, must return an element + return
+ } + + return {element} +} diff --git a/gatsby-config.ts b/gatsby-config.ts index 438655a2dd0..dc347f2a265 100644 --- a/gatsby-config.ts +++ b/gatsby-config.ts @@ -9,14 +9,14 @@ import { ignoreLanguages, } from "./src/utils/languages" +import { IS_PREVIEW } from "./src/utils/env" + const siteUrl = `https://ethereum.org` const ignoreContent = (process.env.IGNORE_CONTENT || "") .split(",") .filter(Boolean) -const isPreviewDeploy = process.env.IS_PREVIEW_DEPLOY === "true" - const ignoreTranslations = ignoreLanguages.map( (lang) => `**/translations\/${lang}` ) @@ -37,17 +37,20 @@ const config: GatsbyConfig = { plugins: [ // i18n support { - resolve: `gatsby-plugin-intl`, + resolve: `gatsby-theme-i18n`, + options: { + defaultLang: defaultLanguage, + prefixDefault: true, + locales: supportedLanguages.length + ? supportedLanguages.join(" ") + : null, + configPath: path.resolve(`./i18n/config.json`), + }, + }, + { + resolve: `gatsby-theme-i18n-react-intl`, options: { - // language JSON resource path - path: path.resolve(`src/intl`), - // supported language - languages: supportedLanguages, - // language file path - defaultLanguage, - // redirect to `/${lang}/` when connecting to `/` - // based on user's browser language preference - redirect: true, + defaultLocale: `./src/intl/en.json`, }, }, // Web app manifest @@ -239,7 +242,7 @@ const config: GatsbyConfig = { // Avoid loading Matomo in preview deploys since NODE_ENV is `production` in // there and it will send testing data as production otherwise -if (!isPreviewDeploy) { +if (!IS_PREVIEW) { config.plugins = [ ...(config.plugins || []), // Matomo analtyics diff --git a/gatsby-node.ts b/gatsby-node.ts index e33a4485248..0e5dd4ce4f3 100644 --- a/gatsby-node.ts +++ b/gatsby-node.ts @@ -18,7 +18,7 @@ import { defaultLanguage, Lang, } from "./src/utils/languages" -import getMessages from "./src/utils/getMessages" +import { IS_DEV } from "./src/utils/env" import redirects from "./redirects.json" const exec = util.promisify(child_process.exec) @@ -153,9 +153,6 @@ export const onCreateNode: GatsbyNode<{ if (slug.includes("/translations/")) { slug = slug.replace("/translations", "") - const split = slug.split("/") - split.splice(1, 1) - isOutdated = await checkIsMdxOutdated(node.fileAbsolutePath) } else { slug = `/${defaultLanguage}${slug}` @@ -193,6 +190,7 @@ export const createPages: GatsbyNode["createPages"] = async ({ }) => { const { createPage, createRedirect } = actions + // server side redirects redirects.forEach((redirect) => { createRedirect({ ...redirect, @@ -271,27 +269,22 @@ export const createPages: GatsbyNode["createPages"] = async ({ const splitSlug = slug.split("/") splitSlug.splice(1, 1, lang) const langSlug = splitSlug.join("/") - createPage({ + createPage({ path: langSlug, component: path.resolve(`src/templates/${template}.tsx`), context: { + language: lang, slug: langSlug, ignoreTranslationBanner: isLegal, isLegal: isLegal, isOutdated: false, isContentEnglish: true, - relativePath: relativePath, // Use English path for template MDX query - // Create `intl` object so `gatsby-plugin-intl` will skip - // generating language variations for this page - intl: { - language: lang, - defaultLanguage, - languages: supportedLanguages, - messages: getMessages("./src/intl/", lang), - routed: true, - originalPath: slug.substr(3), - redirect: false, - }, + relativePath, // Use English path for template MDX query + // gatsby i18n theme context + locale: lang, + hrefLang: lang, + originalPath: langSlug.slice(3), + dateFormat: "MM/DD/YYYY", }, }) } @@ -305,18 +298,13 @@ export const createPages: GatsbyNode["createPages"] = async ({ language, slug, isOutdated: !!node.fields.isOutdated, - relativePath: relativePath, - // Create `intl` object so `gatsby-plugin-intl` will skip - // generating language variations for this page - intl: { - language, - defaultLanguage, - languages: supportedLanguages, - messages: getMessages("./src/intl/", language), - routed: true, - originalPath: slug.substr(3), - redirect: false, - }, + isDefaultLang: language === defaultLanguage, + relativePath, + // gatsby i18n theme context + locale: language, + hrefLang: language, + originalPath: slug.slice(3), + dateFormat: "MM/DD/YYYY", }, }) }) @@ -338,22 +326,22 @@ export const createPages: GatsbyNode["createPages"] = async ({ page, lang ) - createPage({ - path: `/${lang}/${page}/`, + const originalPath = `/${page}/` + const slug = `/${lang}${originalPath}` + + createPage({ + path: slug, component: path.resolve(`src/pages-conditional/${page}.tsx`), context: { - slug: `/${lang}/${page}/`, - intl: { - language: lang, - languages: supportedLanguages, - defaultLanguage, - messages: getMessages("./src/intl/", lang), - routed: true, - originalPath: `/${page}/`, - redirect: false, - }, + language: lang, + slug, isContentEnglish, isOutdated, + // gatsby i18n theme context + locale: lang, + hrefLang: lang, + originalPath, + dateFormat: "MM/DD/YYYY", }, }) } @@ -370,13 +358,21 @@ export const onCreatePage: GatsbyNode["onCreatePage"] = async ({ }) => { const { createPage, deletePage } = actions - const isTranslated = page.context.language !== defaultLanguage + // create routes without the lang prefix e.g. `/{path}` as our i18n plugin + // only creates `/{lang}/{path}` routes. This is useful on dev env to avoid + // getting a 404 since we don't have server side redirects + if (IS_DEV && page.path.startsWith(`/${defaultLanguage}`)) { + const path = page.path.slice(3) + createPage({ ...page, path }) + } + + const isTranslated = page.context.locale !== defaultLanguage const hasNoContext = page.context.isOutdated === undefined if (isTranslated && hasNoContext) { const { isOutdated, isContentEnglish } = await checkIsPageOutdated( - page.context.intl.originalPath, - page.context.language + page.context.originalPath, + page.context.locale ) deletePage(page) createPage({ diff --git a/gatsby-ssr.tsx b/gatsby-ssr.tsx index 7dbc3a3d757..7b94aef3c86 100644 --- a/gatsby-ssr.tsx +++ b/gatsby-ssr.tsx @@ -10,9 +10,11 @@ import type { GatsbySSR } from "gatsby" import Layout from "./src/components/Layout" +import { Context } from "./src/types" + // Prevents from unmounting on page transitions // https://www.gatsbyjs.com/docs/layout-components/#how-to-prevent-layout-components-from-unmounting -export const wrapPageElement: GatsbySSR["wrapPageElement"] = ({ +export const wrapPageElement: GatsbySSR["wrapPageElement"] = ({ element, props, }) => { diff --git a/i18n/config.json b/i18n/config.json new file mode 100644 index 00000000000..b9909545087 --- /dev/null +++ b/i18n/config.json @@ -0,0 +1,370 @@ +[ + { + "code": "en", + "hrefLang": "en", + "name": "English", + "localName": "English", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "ar", + "hrefLang": "ar", + "name": "Arabic", + "localName": "العربية", + "langDir": "rtl", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "az", + "hrefLang": "az", + "name": "Azerbaijani", + "localName": "Azərbaycan", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "bg", + "hrefLang": "bg", + "name": "Bulgarian", + "localName": "български", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "bn", + "hrefLang": "bn", + "name": "Bengali", + "localName": "বাংলা", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "ca", + "hrefLang": "ca", + "name": "Catalan", + "localName": "Català", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "cs", + "hrefLang": "cs", + "name": "Czech", + "localName": "Čeština", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "da", + "hrefLang": "da", + "name": "Danish", + "localName": "Dansk", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "de", + "hrefLang": "de", + "name": "German", + "localName": "Deutsch", + "langDir": "ltr", + "dateFormat": "DD/MM/YYYY" + }, + { + "code": "el", + "hrefLang": "el", + "name": "Greek", + "localName": "Ελληνικά", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "es", + "hrefLang": "es", + "name": "Spanish", + "localName": "Español", + "langDir": "ltr", + "dateFormat": "DD/MM/YYYY" + }, + { + "code": "fa", + "hrefLang": "fa", + "name": "Farsi", + "localName": "فارسی", + "langDir": "rtl", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "fi", + "hrefLang": "fi", + "name": "Finnish", + "localName": "Suomi", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "fr", + "hrefLang": "fr", + "name": "French", + "localName": "Français", + "langDir": "ltr", + "dateFormat": "DD/MM/YYYY" + }, + { + "code": "gl", + "hrefLang": "gl", + "name": "Galician", + "localName": "Galego", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "hi", + "hrefLang": "hi", + "name": "Hindi", + "localName": "हिन्दी", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "hr", + "hrefLang": "hr", + "name": "Croatian", + "localName": "Hrvatski", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "hu", + "hrefLang": "hu", + "name": "Hungarian", + "localName": "Magyar", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "id", + "hrefLang": "id", + "name": "Indonesian", + "localName": "Bahasa Indonesia", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "ig", + "hrefLang": "ig", + "name": "Igbo", + "localName": "Ibo", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "it", + "hrefLang": "it", + "name": "Italian", + "localName": "Italiano", + "langDir": "ltr", + "dateFormat": "DD/MM/YYYY" + }, + { + "code": "ja", + "hrefLang": "ja", + "name": "Japanese", + "localName": "日本語", + "langDir": "ltr", + "dateFormat": "YYYY/MM/DD" + }, + { + "code": "ka", + "hrefLang": "ka", + "name": "Georgian", + "localName": "ქართული", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "ko", + "hrefLang": "ko", + "name": "Korean", + "localName": "한국어", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "lt", + "hrefLang": "lt", + "name": "Lithuanian", + "localName": "Lietuvis", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "ml", + "hrefLang": "ml", + "name": "Malayalam", + "localName": "മലയാളം", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "mr", + "hrefLang": "mr", + "name": "Marathi", + "localName": "मराठी", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "ms", + "hrefLang": "ms", + "name": "Malay", + "localName": "Melayu", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "nl", + "hrefLang": "nl", + "name": "Dutch", + "localName": "Nederlands", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "nb", + "hrefLang": "nb", + "name": "Norwegian", + "localName": "Norsk", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "pl", + "hrefLang": "pl", + "name": "Polish", + "localName": "Polski", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "pt", + "hrefLang": "pt", + "name": "Portuguese", + "localName": "Português", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "pt-br", + "hrefLang": "pt-br", + "name": "Portuguese (Brazilian)", + "localName": "Português", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "ro", + "hrefLang": "ro", + "name": "Romanian", + "localName": "Română", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "ru", + "hrefLang": "ru", + "name": "Russian", + "localName": "Pусский", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "se", + "hrefLang": "se", + "name": "Swedish", + "localName": "Svenska", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "sk", + "hrefLang": "sk", + "name": "Slovak", + "localName": "Slovenský", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "sl", + "hrefLang": "sl", + "name": "Slovenian", + "localName": "Slovenščina", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "sr", + "hrefLang": "sr", + "name": "Serbian", + "localName": "Српски", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "sw", + "hrefLang": "sw", + "name": "Swahili", + "localName": "Kiswahili", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "th", + "hrefLang": "th", + "name": "Thai", + "localName": "ภาษาไทย", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "tr", + "hrefLang": "tr", + "name": "Turkish", + "localName": "Türkçe", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "uk", + "hrefLang": "uk", + "name": "Ukrainian", + "localName": "Українська", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "vi", + "hrefLang": "vi", + "name": "Vietnamese", + "localName": "Tiếng Việt", + "langDir": "ltr", + "dateFormat": "MM/DD/YYYY" + }, + { + "code": "zh", + "hrefLang": "zh", + "name": "Chinese Simplified", + "localName": "简体中文", + "langDir": "ltr", + "dateFormat": "YYYY-MM-DD" + }, + { + "code": "zh-tw", + "hrefLang": "zh-tw", + "name": "Chinese Traditional", + "localName": "繁體中文", + "langDir": "ltr", + "dateFormat": "YYYY-MM-DD" + } +] diff --git a/overrides.d.ts b/overrides.d.ts index f72afd2042b..39335149c51 100644 --- a/overrides.d.ts +++ b/overrides.d.ts @@ -3,15 +3,7 @@ declare module "gatsby-plugin-image" declare module "*developer-docs-links.yaml" { - import { TranslationKey } from "./src/utils/translations" - - export interface DeveloperDocsLink { - id: TranslationKey - to: string - path: string - description: TranslationKey - items: Array - } + import { DeveloperDocsLink } from "./src/types" const content: Array export default content } diff --git a/package.json b/package.json index 10abb575056..2e2cad7e632 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ethereum-org-website", - "version": "4.2.0", + "version": "4.8.0", "description": "Website of ethereum.org", "main": "index.js", "repository": "git@github.com:ethereum/ethereum-org-website.git", @@ -16,16 +16,18 @@ "algoliasearch": "^4.3.0", "axios": "^0.21.2", "babel-plugin-styled-components": "^1.10.7", + "browser-lang": "^0.1.0", + "browserslist": "^4.21.0", "clipboard": "^2.0.6", "cross-fetch": "^3.1.5", "dotenv": "^8.2.0", + "embla-carousel-react": "^6.2.0", "ethereum-blockies-base64": "^1.0.2", "focus-trap-react": "^8.11.2", "framer-motion": "^4.1.3", "gatsby": "^4.15.0", "gatsby-plugin-gatsby-cloud": "^4.3.0", "gatsby-plugin-image": "^2.0.0", - "gatsby-plugin-intl": "^0.3.3", "gatsby-plugin-manifest": "^4.10.1", "gatsby-plugin-matomo": "^0.9.0", "gatsby-plugin-mdx": "^2.14.1", @@ -41,6 +43,8 @@ "gatsby-remark-images": "^6.0.0", "gatsby-remark-reading-time": "^1.1.0", "gatsby-source-filesystem": "^4.0.0", + "gatsby-theme-i18n": "^3.0.0", + "gatsby-theme-i18n-react-intl": "^3.0.0", "gatsby-transformer-csv": "^4.0.0", "gatsby-transformer-gitinfo": "^1.1.0", "gatsby-transformer-json": "^4.11.0", @@ -60,14 +64,16 @@ "react-helmet": "^6.1.0", "react-icons": "^4.3.1", "react-instantsearch-dom": "^6.6.0", + "react-intl": "^3.12.1", "react-select": "^4.3.0", - "recharts": "1.8.5", + "recharts": "^2.1.9", "styled-components": "^5.1.1", "styled-system": "^5.1.5", "unist-util-visit-parents": "^2.1.2" }, "devDependencies": { "@netlify/functions": "^1.0.0", + "@types/browser-lang": "^0.1.0", "@types/luxon": "^2.3.2", "@types/mdx-js__react": "^1.5.5", "@types/node": "^17.0.23", @@ -79,6 +85,7 @@ "github-slugger": "^1.3.0", "husky": "^4.2.5", "identity-obj-proxy": "^3.0.0", + "minimist": "^1.2.6", "prettier": "^2.2.1", "pretty-quick": "^3.1.0", "react-test-renderer": "^17.0.1", @@ -87,11 +94,12 @@ "scripts": { "build": "gatsby build", "build:lambda": "netlify-lambda build src/lambda", + "build:10gb": "NODE_OPTIONS=--max-old-space-size=10240 gatsby build", "clean": "gatsby clean", - "copy-contributors": "node src/scripts/copy-contributors.js", + "crowdin-clean": "rm -rf .crowdin && mkdir .crowdin", + "crowdin-import": "ts-node src/scripts/crowdin-import.ts", "format": "prettier --write \"**/*.{js,jsx,json,md}\"", "generate-heading-ids": "node src/scripts/generate-heading-ids.js", - "merge-translations": "node src/scripts/merge-translations.js", "start": "gatsby develop", "start:lambda": "netlify-lambda serve src/lambda", "start:static": "gatsby build && gatsby serve", diff --git a/src/assets/eth-home-icon.svg b/src/assets/eth-home-icon.svg new file mode 100644 index 00000000000..fe48ec41843 --- /dev/null +++ b/src/assets/eth-home-icon.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/exchanges/1inch.png b/src/assets/exchanges/1inch.png index 26dd2cd15a2..520fbc46679 100644 Binary files a/src/assets/exchanges/1inch.png and b/src/assets/exchanges/1inch.png differ diff --git a/src/assets/feedback-thumbs-up.svg b/src/assets/feedback-thumbs-up.svg new file mode 100644 index 00000000000..96a1b1c5cbd --- /dev/null +++ b/src/assets/feedback-thumbs-up.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/staking/green-check-product-glyph.svg b/src/assets/staking/green-check-product-glyph.svg index e26e9d317b4..a1896e1ef39 100644 --- a/src/assets/staking/green-check-product-glyph.svg +++ b/src/assets/staking/green-check-product-glyph.svg @@ -1,4 +1,4 @@ - - + + diff --git a/src/assets/staking/warning-product-glyph.svg b/src/assets/staking/warning-product-glyph.svg index 477b9b9db60..61bcaebd8c6 100644 --- a/src/assets/staking/warning-product-glyph.svg +++ b/src/assets/staking/warning-product-glyph.svg @@ -1,4 +1,4 @@ - - + + diff --git a/src/assets/wallets/1inch.png b/src/assets/wallets/1inch.png new file mode 100644 index 00000000000..520fbc46679 Binary files /dev/null and b/src/assets/wallets/1inch.png differ diff --git a/src/assets/wallets/aktionariat.png b/src/assets/wallets/aktionariat.png new file mode 100644 index 00000000000..a6668c20e22 Binary files /dev/null and b/src/assets/wallets/aktionariat.png differ diff --git a/src/assets/wallets/alpha.png b/src/assets/wallets/alpha.png index 6cb94600a68..2c411924569 100644 Binary files a/src/assets/wallets/alpha.png and b/src/assets/wallets/alpha.png differ diff --git a/src/assets/wallets/ambire.png b/src/assets/wallets/ambire.png new file mode 100644 index 00000000000..3c357405263 Binary files /dev/null and b/src/assets/wallets/ambire.png differ diff --git a/src/assets/wallets/brave.png b/src/assets/wallets/brave.png new file mode 100644 index 00000000000..afe6600bdc4 Binary files /dev/null and b/src/assets/wallets/brave.png differ diff --git a/src/assets/wallets/bridge.png b/src/assets/wallets/bridge.png new file mode 100644 index 00000000000..51da90fba55 Binary files /dev/null and b/src/assets/wallets/bridge.png differ diff --git a/src/assets/wallets/browser.svg b/src/assets/wallets/browser.svg new file mode 100644 index 00000000000..ad1af681983 --- /dev/null +++ b/src/assets/wallets/browser.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/wallets/buy_crypto.svg b/src/assets/wallets/buy_crypto.svg new file mode 100644 index 00000000000..6533fb212a5 --- /dev/null +++ b/src/assets/wallets/buy_crypto.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/wallets/coinwallet.png b/src/assets/wallets/coinwallet.png new file mode 100644 index 00000000000..a594945d2d3 Binary files /dev/null and b/src/assets/wallets/coinwallet.png differ diff --git a/src/assets/wallets/connect_dapps.svg b/src/assets/wallets/connect_dapps.svg new file mode 100644 index 00000000000..8bf0d7fab22 --- /dev/null +++ b/src/assets/wallets/connect_dapps.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/wallets/desktop.svg b/src/assets/wallets/desktop.svg new file mode 100644 index 00000000000..895de1bf7f8 --- /dev/null +++ b/src/assets/wallets/desktop.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/wallets/eip1559.svg b/src/assets/wallets/eip1559.svg new file mode 100644 index 00000000000..854f73debbf --- /dev/null +++ b/src/assets/wallets/eip1559.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/wallets/ens_support.svg b/src/assets/wallets/ens_support.svg new file mode 100644 index 00000000000..7340241a682 --- /dev/null +++ b/src/assets/wallets/ens_support.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/wallets/erc_20_support.svg b/src/assets/wallets/erc_20_support.svg new file mode 100644 index 00000000000..faf446607dc --- /dev/null +++ b/src/assets/wallets/erc_20_support.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/wallets/filter_burger.svg b/src/assets/wallets/filter_burger.svg new file mode 100644 index 00000000000..c512c27bcab --- /dev/null +++ b/src/assets/wallets/filter_burger.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/wallets/find-wallet-hero.png b/src/assets/wallets/find-wallet-hero.png index ad559cc1505..d6659f20c86 100644 Binary files a/src/assets/wallets/find-wallet-hero.png and b/src/assets/wallets/find-wallet-hero.png differ diff --git a/src/assets/wallets/foxwallet.png b/src/assets/wallets/foxwallet.png new file mode 100644 index 00000000000..3c531ca1193 Binary files /dev/null and b/src/assets/wallets/foxwallet.png differ diff --git a/src/assets/wallets/frame.png b/src/assets/wallets/frame.png new file mode 100644 index 00000000000..ec7825167a6 Binary files /dev/null and b/src/assets/wallets/frame.png differ diff --git a/src/assets/wallets/frame.svg b/src/assets/wallets/frame.svg new file mode 100644 index 00000000000..7ef0e026e76 --- /dev/null +++ b/src/assets/wallets/frame.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/wallets/gas_fee_customization.svg b/src/assets/wallets/gas_fee_customization.svg new file mode 100644 index 00000000000..71ec374baeb --- /dev/null +++ b/src/assets/wallets/gas_fee_customization.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/wallets/gnosis.png b/src/assets/wallets/gnosis.png index 11f54e2c7f4..fc265549734 100644 Binary files a/src/assets/wallets/gnosis.png and b/src/assets/wallets/gnosis.png differ diff --git a/src/assets/wallets/hardware.svg b/src/assets/wallets/hardware.svg new file mode 100644 index 00000000000..921b5287d09 --- /dev/null +++ b/src/assets/wallets/hardware.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/wallets/hardware_support.svg b/src/assets/wallets/hardware_support.svg new file mode 100644 index 00000000000..a2d4ef3c8b5 --- /dev/null +++ b/src/assets/wallets/hardware_support.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/wallets/layer_2.svg b/src/assets/wallets/layer_2.svg new file mode 100644 index 00000000000..f1182d772c5 --- /dev/null +++ b/src/assets/wallets/layer_2.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/wallets/mew.png b/src/assets/wallets/mew.png new file mode 100644 index 00000000000..48c42dc1450 Binary files /dev/null and b/src/assets/wallets/mew.png differ diff --git a/src/assets/wallets/mobile.svg b/src/assets/wallets/mobile.svg new file mode 100644 index 00000000000..8613e708fd7 --- /dev/null +++ b/src/assets/wallets/mobile.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/wallets/multisig.svg b/src/assets/wallets/multisig.svg new file mode 100644 index 00000000000..337f41de1fa --- /dev/null +++ b/src/assets/wallets/multisig.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/wallets/nft_support.svg b/src/assets/wallets/nft_support.svg new file mode 100644 index 00000000000..706c487f6ec --- /dev/null +++ b/src/assets/wallets/nft_support.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/wallets/non_custodial.svg b/src/assets/wallets/non_custodial.svg new file mode 100644 index 00000000000..f545ed6b4d0 --- /dev/null +++ b/src/assets/wallets/non_custodial.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/wallets/open_source.svg b/src/assets/wallets/open_source.svg new file mode 100644 index 00000000000..91f3ad6962f --- /dev/null +++ b/src/assets/wallets/open_source.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/wallets/pillar.png b/src/assets/wallets/pillar.png index bb73e947a25..6a4c1d26a57 100644 Binary files a/src/assets/wallets/pillar.png and b/src/assets/wallets/pillar.png differ diff --git a/src/assets/wallets/rpc_importing.svg b/src/assets/wallets/rpc_importing.svg new file mode 100644 index 00000000000..89d2be3b0a0 --- /dev/null +++ b/src/assets/wallets/rpc_importing.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/wallets/social_recover.svg b/src/assets/wallets/social_recover.svg new file mode 100644 index 00000000000..09f27fd85f3 --- /dev/null +++ b/src/assets/wallets/social_recover.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/wallets/staking.svg b/src/assets/wallets/staking.svg new file mode 100644 index 00000000000..3d3e85e3d0e --- /dev/null +++ b/src/assets/wallets/staking.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/wallets/swap.svg b/src/assets/wallets/swap.svg new file mode 100644 index 00000000000..0806eb982e4 --- /dev/null +++ b/src/assets/wallets/swap.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/wallets/tallyho.png b/src/assets/wallets/tallyho.png new file mode 100644 index 00000000000..1221f3ee281 Binary files /dev/null and b/src/assets/wallets/tallyho.png differ diff --git a/src/assets/wallets/walletconnect.svg b/src/assets/wallets/walletconnect.svg new file mode 100644 index 00000000000..564797e2dcf --- /dev/null +++ b/src/assets/wallets/walletconnect.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/wallets/web3auth.png b/src/assets/wallets/web3auth.png new file mode 100644 index 00000000000..875563d9045 Binary files /dev/null and b/src/assets/wallets/web3auth.png differ diff --git a/src/assets/wallets/withdraw_crypto.svg b/src/assets/wallets/withdraw_crypto.svg new file mode 100644 index 00000000000..a5686ec80f8 --- /dev/null +++ b/src/assets/wallets/withdraw_crypto.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/what-is-eth/eth.png b/src/assets/what-is-eth/eth.png new file mode 100644 index 00000000000..c20ab8ad156 Binary files /dev/null and b/src/assets/what-is-eth/eth.png differ diff --git a/src/components/AdoptionChart.tsx b/src/components/AdoptionChart.tsx new file mode 100644 index 00000000000..b15b228cc12 --- /dev/null +++ b/src/components/AdoptionChart.tsx @@ -0,0 +1,86 @@ +import React from "react" +import styled, { useTheme } from "styled-components" + +const Container = styled.div` + display: flex; + flex-direction: row; +` + +const Column = styled.div` + display: flex; + flex-direction: column-reverse; + margin-left: 0.5rem; + + &:first-child { + margin-left: 0; + } + + @media (min-width: ${(props) => props.theme.breakpoints.m}) { + margin-left: 1rem; + } +` + +const Cell = styled.div<{ color?: string }>` + border: 1px solid ${({ theme, color }) => (color ? color : theme.colors.text)}; + color: ${({ theme, color }) => (color ? color : theme.colors.text)}; + padding: 0.8rem 0.5rem; + font-size: 0.9rem; + font-weight: 700; + line-height: 1; + text-align: center; + + &:last-child { + border-top-left-radius: 1rem; + border-top-right-radius: 1rem; + } + + &:nth-child(-n + 2) { + border-bottom-left-radius: 1rem; + border-bottom-right-radius: 1rem; + } + + @media (min-width: ${(props) => props.theme.breakpoints.m}) { + padding: 0.8rem 1.2rem; + } +` + +const ColumnName = styled(Cell)` + border: 0; + padding-top: 1.5rem; +` + +interface IProps {} + +const AdoptionChart: React.FC = () => { + const { isDark } = useTheme() + + return ( + + + 2010 + Investors + + + + 2014 + Investors + Developers + Companies + + + + Now + Investors + Developers + Companies + Artists + Musicians + Writers + Gamers + Refugees + + + ) +} + +export default AdoptionChart diff --git a/src/components/BannerGrid/index.tsx b/src/components/BannerGrid/index.tsx new file mode 100644 index 00000000000..9f070162204 --- /dev/null +++ b/src/components/BannerGrid/index.tsx @@ -0,0 +1,97 @@ +import styled from "styled-components" + +export const Banner = styled.div` + width: 100%; + display: flex; + background: ${(props) => props.theme.colors.bannerGridGradient}; + + h2 { + margin-top: 0; + } + + ul { + margin-bottom: 0; + } + + flex-flow: column nowrap; + + @media (min-width: ${(props) => props.theme.breakpoints.l}) { + flex-flow: row nowrap; + } +` + +export const BannerBody = styled.div` + flex: 4; + padding: 40px; +` + +export const BannerImage = styled.div` + display: flex; + justify-content: end; + flex: 2; + align-self: end; +` + +export const BannerGrid = styled.div` + display: grid; + grid-template-columns: repeat(1, 1fr); + grid-column-gap: 0px; + grid-row-gap: 0px; + + @media (min-width: ${(props) => props.theme.breakpoints.m}) { + grid-template-columns: repeat(2, 1fr); + grid-template-rows: repeat(3, 1fr); + } + + @media (min-width: ${(props) => props.theme.breakpoints.l}) { + grid-template-columns: repeat(3, 1fr); + grid-template-rows: repeat(2, 1fr); + } +` + +export const BannerGridCell = styled.div` + padding: 2rem 3rem; + display: flex; + flex-direction: column; + + border-top: 1px solid ${({ theme }) => theme.colors.searchBackground}; + + border-left: none; + &:first-child { + border-top: none; + } + + @media (min-width: ${(props) => props.theme.breakpoints.m}) { + border-left: 1px solid ${({ theme }) => theme.colors.searchBackground}; + &:nth-child(-n + 2) { + border-top: none; + } + &:nth-child(2n + 1) { + border-left: none; + } + } + + @media (min-width: ${(props) => props.theme.breakpoints.l}) { + &:nth-child(-n + 2) { + border-top: 1px solid ${({ theme }) => theme.colors.searchBackground}; + } + &:nth-child(2n + 1) { + border-left: 1px solid ${({ theme }) => theme.colors.searchBackground}; + } + + &:nth-child(-n + 3) { + border-top: none; + justify-content: start; + padding-top: 0; + } + &:first-child, + &:nth-child(3n + 1) { + padding-left: 0; + border-left: none; + } + &:nth-child(n + 4) { + justify-content: start; + padding-bottom: 0; + } + } +` diff --git a/src/components/BeaconChainActions.tsx b/src/components/BeaconChainActions.tsx index 58028ca4248..d7710ee4f21 100644 --- a/src/components/BeaconChainActions.tsx +++ b/src/components/BeaconChainActions.tsx @@ -2,7 +2,7 @@ import React from "react" import { useStaticQuery, graphql } from "gatsby" import { getImage } from "gatsby-plugin-image" import styled from "styled-components" -import { useIntl } from "gatsby-plugin-intl" +import { useIntl } from "react-intl" import { translateMessageId } from "../utils/translations" diff --git a/src/components/Breadcrumbs.js b/src/components/Breadcrumbs.tsx similarity index 76% rename from src/components/Breadcrumbs.js rename to src/components/Breadcrumbs.tsx index c91e4b56842..f2b4b4dabf6 100644 --- a/src/components/Breadcrumbs.js +++ b/src/components/Breadcrumbs.tsx @@ -1,10 +1,10 @@ import React from "react" import styled from "styled-components" -import { useIntl } from "gatsby-plugin-intl" +import { useIntl } from "react-intl" import Link from "./Link" -import { supportedLanguages } from "../utils/languages" -import { translateMessageId } from "../utils/translations" +import { isLang, supportedLanguages } from "../utils/languages" +import { isTranslationKey, translateMessageId } from "../utils/translations" const ListContainer = styled.nav` margin-bottom: 2rem; @@ -47,6 +47,11 @@ const CrumbLink = styled(Link)` } ` +export interface IProps { + slug: string + startDepth?: number +} + // Generate crumbs from slug // e.g. "/en/eth2/proof-of-stake/" will generate: // [ @@ -60,20 +65,26 @@ const CrumbLink = styled(Link)` // { fullPath: "/en/eth2/", text: "ETH2" }, // { fullPath: "/en/eth2/proof-of-stake/", text: "PROOF OF STAKE" }, // ] -const Breadcrumbs = ({ slug, startDepth = 0, ...restProps }) => { +const Breadcrumbs: React.FC = ({ + slug, + startDepth = 0, + ...restProps +}) => { const intl = useIntl() - const split = slug.split("/") - const sliced = split.filter((item) => !!item).slice(startDepth) + const slugChunk = slug.split("/") + const sliced = slugChunk.filter((item) => !!item).slice(startDepth) const crumbs = sliced.map((path, idx) => { // If homepage (e.g. "en"), set text to "home" translation - const text = supportedLanguages.includes(path) + const text = isLang(path) ? translateMessageId("page-index-meta-title", intl) - : translateMessageId(path, intl) + : isTranslationKey(path) + ? translateMessageId(path, intl) + : "" return { - fullPath: split.slice(0, idx + 2 + startDepth).join("/") + "/", + fullPath: slugChunk.slice(0, idx + 2 + startDepth).join("/") + "/", text: text.toUpperCase(), } }) diff --git a/src/components/BugBountyCards.js b/src/components/BugBountyCards.tsx similarity index 90% rename from src/components/BugBountyCards.js rename to src/components/BugBountyCards.tsx index 4cf62aabaf9..b084c10fd9c 100644 --- a/src/components/BugBountyCards.js +++ b/src/components/BugBountyCards.tsx @@ -1,8 +1,9 @@ import React from "react" import styled from "styled-components" +import { TranslationKey } from "../utils/translations" import ButtonLink from "./ButtonLink" -import Translation from "../components/Translation" +import Translation from "./Translation" const CardRow = styled.div` display: flex; @@ -108,7 +109,22 @@ const Text = styled.div` margin-top: 0.5rem; ` -const bugBountyCardsInfo = [ +export interface BugBountyCardInfo { + lowLabelTranslationId?: TranslationKey + mediumLabelTranslationId?: TranslationKey + highLabelTranslationId?: TranslationKey + criticalLabelTranslationId?: TranslationKey + h2TranslationId: TranslationKey + descriptionTranslationId: TranslationKey + subDescriptionTranslationId: TranslationKey + subHeader1TranslationId: TranslationKey + severityList: Array + subHeader2TranslationId: TranslationKey + textTranslationId: TranslationKey + styledButtonTranslationId: TranslationKey +} + +const bugBountyCardsInfo: Array = [ { lowLabelTranslationId: "page-upgrades-bug-bounty-card-label-2", h2TranslationId: "page-upgrades-bug-bounty-card-low", @@ -165,7 +181,9 @@ const bugBountyCardsInfo = [ }, ] -const BugBountyCards = () => ( +export interface IProps {} + +const BugBountyCards: React.FC = () => ( {bugBountyCardsInfo.map((card, idx) => ( diff --git a/src/components/BugBountyPoints.js b/src/components/BugBountyPoints.tsx similarity index 88% rename from src/components/BugBountyPoints.js rename to src/components/BugBountyPoints.tsx index 419934c1b0e..490492e255e 100644 --- a/src/components/BugBountyPoints.js +++ b/src/components/BugBountyPoints.tsx @@ -84,10 +84,23 @@ export const TokenLogo = graphql` const USD_PER_POINT = 2 -const BugBountyPoints = () => { - const [state, setState] = useState({ - currentETHPriceUSD: "", - currentDAIPriceUSD: "", +interface State { + currentETHPriceUSD: number + currentDAIPriceUSD: number + hasError: boolean +} + +type GetPriceResponse = { + ethereum: { usd: number } + dai: { usd: number } +} + +export interface IProps {} + +const BugBountyPoints: React.FC = () => { + const [state, setState] = useState({ + currentETHPriceUSD: 1, + currentDAIPriceUSD: 1, hasError: false, }) const themeContext = useContext(ThemeContext) @@ -95,7 +108,7 @@ const BugBountyPoints = () => { useEffect(() => { axios - .get( + .get( "https://api.coingecko.com/api/v3/simple/price?ids=ethereum%2Cdai&vs_currencies=usd" ) .then((response) => { @@ -112,6 +125,7 @@ const BugBountyPoints = () => { .catch((error) => { console.error(error) setState({ + ...state, hasError: true, }) }) @@ -119,8 +133,12 @@ const BugBountyPoints = () => { const isLoading = !state.currentETHPriceUSD - const pointsInETH = (USD_PER_POINT / state.currentETHPriceUSD).toFixed(5) - const pointsInDAI = (USD_PER_POINT / state.currentDAIPriceUSD).toFixed(5) + const pointsInETH = !state.hasError + ? (USD_PER_POINT / state.currentETHPriceUSD!).toFixed(5) + : 0 + const pointsInDAI = !state.hasError + ? (USD_PER_POINT / state.currentDAIPriceUSD!).toFixed(5) + : 0 const tooltipContent = (
diff --git a/src/components/ButtonDropdown.js b/src/components/ButtonDropdown.tsx similarity index 83% rename from src/components/ButtonDropdown.js rename to src/components/ButtonDropdown.tsx index 83f6100e8fd..957fee6cc5f 100644 --- a/src/components/ButtonDropdown.js +++ b/src/components/ButtonDropdown.tsx @@ -1,7 +1,7 @@ // Libraries import React, { useState, createRef } from "react" import styled from "styled-components" -import { useIntl } from "gatsby-plugin-intl" +import { useIntl } from "react-intl" import { motion } from "framer-motion" // Components @@ -12,7 +12,7 @@ import { ButtonSecondary } from "./SharedStyledComponents" // Utils import { useOnClickOutside } from "../hooks/useOnClickOutside" -import { translateMessageId } from "../utils/translations" +import { translateMessageId, TranslationKey } from "../utils/translations" import { trackCustomEvent } from "../utils/matomo" const Container = styled.div` @@ -113,16 +113,38 @@ const NakedNavLink = styled.div` } ` -const ButtonDropdown = ({ list, className }) => { - const [isOpen, setIsOpen] = useState(false) +export interface ListItem { + text: TranslationKey + to?: string + matomo?: { + eventCategory: string + eventAction: string + eventName: string + } + callback?: (idx: number) => void +} + +export interface List { + text: TranslationKey + ariaLabel: string + items: Array +} + +export interface IProps { + list: List + className?: string +} + +const ButtonDropdown: React.FC = ({ list, className }) => { + const [isOpen, setIsOpen] = useState(false) const intl = useIntl() - const ref = createRef() + const ref = createRef() useOnClickOutside(ref, () => setIsOpen(false)) // Toggle on `enter` key - const onKeyDownHandler = (e) => { - if (e.keyCode === 13) { + const onKeyDownHandler = (e: React.KeyboardEvent): void => { + if (e.key === "13") { setIsOpen(!isOpen) } } @@ -136,7 +158,7 @@ const ButtonDropdown = ({ list, className }) => {