Skip to content

Commit fdafee1

Browse files
committed
Merge branch 'dev' into ssr-what-is-ethereum
2 parents edcb1a7 + 42e6555 commit fdafee1

File tree

406 files changed

+1774
-4219
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

406 files changed

+1774
-4219
lines changed

.eslintrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"^(assert|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|https|module|net|os|path|punycode|querystring|readline|repl|stream|string_decoder|sys|timers|tls|tty|url|util|vm|zlib|freelist|v8|process|async_hooks|http2|perf_hooks)(/.*|$)"
2525
],
2626
// Packages. `react` related packages come first.
27-
// Also, put `react-icons` in sorting order not with `react`
27+
// Also, put `react-*` in sorting order not with `react`
2828
["^react(?!-.)$", "^\\w", "^@\\w"],
2929
// From the `types` directory.
3030
["^@/lib/types", "^@/lib/interfaces"],

.husky/pre-commit

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
npx lint-staged
1+
npx lint-staged

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ pnpm events-import # Import community events
179179
- `@radix-ui/*` - Accessible component primitives
180180
- `tailwind-variants` - Component variant patterns
181181
- `framer-motion` - Animation library
182-
- `react-icons` - Icon library
182+
- `lucide-react` - Icon library
183183

184184
### Content & Data
185185

app/[locale]/10years/_components/Stories.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
"use client"
22

33
import { useState } from "react"
4-
import { FaXTwitter } from "react-icons/fa6"
54

5+
import Twitter from "@/components/icons/twitter.svg"
66
import { Button, ButtonLink } from "@/components/ui/buttons/Button"
77

88
import { cn } from "@/lib/utils/cn"
@@ -96,7 +96,7 @@ const Stories = ({ stories }: StoriesProps) => {
9696
hideArrow
9797
className="text-sm"
9898
>
99-
<FaXTwitter className="h-5 w-5 text-body" />
99+
<Twitter className="text-xl text-body" />
100100
</ButtonLink>
101101
</div>
102102
)}
@@ -175,7 +175,7 @@ const Stories = ({ stories }: StoriesProps) => {
175175
hideArrow
176176
className="text-sm"
177177
>
178-
<FaXTwitter className="h-5 w-5 text-body" />
178+
<Twitter className="h-5 w-5 text-body" />
179179
</ButtonLink>
180180
</div>
181181
)}

app/[locale]/10years/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
348348
/>
349349
<h3>{t("page-10-year-ideas-title")}</h3>
350350
<p>{t("page-10-year-ideas-description")}</p>
351-
<ButtonLink href="mailto:[email protected]" hideArrow>
351+
<ButtonLink href="mailto:[email protected]">
352352
{t("page-10-year-ideas-cta")}
353353
</ButtonLink>
354354
</div>
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
"use client"
2+
3+
import React, { useState } from "react"
4+
5+
import Github from "@/components/icons/github.svg"
6+
import Translation from "@/components/Translation"
7+
import { Button } from "@/components/ui/buttons/Button"
8+
import { ButtonLink } from "@/components/ui/buttons/Button"
9+
import Modal from "@/components/ui/dialog-modal"
10+
import { Flex } from "@/components/ui/flex"
11+
12+
import { trackCustomEvent } from "@/lib/utils/matomo"
13+
14+
import { useBreakpointValue } from "@/hooks/useBreakpointValue"
15+
16+
const TutorialSubmitModal = ({
17+
dir,
18+
}: Pick<React.HTMLAttributes<React.JSX.Element>, "dir">) => {
19+
const [isModalOpen, setModalOpen] = useState(false)
20+
21+
const modalSize = useBreakpointValue({ base: "xl", md: "md" } as const)
22+
23+
return (
24+
<>
25+
<Modal
26+
open={isModalOpen}
27+
onOpenChange={(open) => setModalOpen(open)}
28+
size={modalSize}
29+
contentProps={{ dir }}
30+
title={
31+
<Translation id="page-developers-tutorials:page-tutorial-submit-btn" />
32+
}
33+
>
34+
<p className="mb-6">
35+
<Translation id="page-developers-tutorials:page-tutorial-listing-policy-intro" />
36+
</p>
37+
<Flex className="flex-col gap-2 md:flex-row">
38+
<Flex className="w-full flex-col justify-between rounded-sm border border-border p-4">
39+
<b>
40+
<Translation id="page-developers-tutorials:page-tutorial-create-an-issue" />
41+
</b>
42+
<p className="mb-6">
43+
<Translation id="page-developers-tutorials:page-tutorial-create-an-issue-desc" />
44+
</p>
45+
<ButtonLink
46+
variant="outline"
47+
href="https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=Type%3A+Feature&template=suggest_tutorial.yaml&title="
48+
>
49+
<Github />
50+
<Translation id="page-developers-tutorials:page-tutorial-raise-issue-btn" />
51+
</ButtonLink>
52+
</Flex>
53+
</Flex>
54+
</Modal>
55+
56+
<Button
57+
className="px-3 py-2 text-body"
58+
variant="outline"
59+
onClick={() => {
60+
setModalOpen(true)
61+
trackCustomEvent({
62+
eventCategory: "tutorials tags",
63+
eventAction: "click",
64+
eventName: "submit",
65+
})
66+
}}
67+
>
68+
<Translation id="page-developers-tutorials:page-tutorial-submit-btn" />
69+
</Button>
70+
</>
71+
)
72+
}
73+
74+
TutorialSubmitModal.displayName = "TutorialSubmitModal"
75+
76+
export default TutorialSubmitModal

app/[locale]/developers/tutorials/_components/tutorials.tsx

Lines changed: 10 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,14 @@ import React, {
99
useState,
1010
} from "react"
1111
import { useLocale } from "next-intl"
12-
import { FaGithub } from "react-icons/fa"
1312

1413
import { ITutorial, Lang } from "@/lib/types"
1514

1615
import Emoji from "@/components/Emoji"
17-
import FeedbackCard from "@/components/FeedbackCard"
18-
import MainArticle from "@/components/MainArticle"
1916
import Translation from "@/components/Translation"
2017
import { getSkillTranslationId } from "@/components/TutorialMetadata"
2118
import TutorialTags from "@/components/TutorialTags"
22-
import { Button, ButtonLink } from "@/components/ui/buttons/Button"
23-
import Modal from "@/components/ui/dialog-modal"
19+
import { Button } from "@/components/ui/buttons/Button"
2420
import { Flex, FlexProps } from "@/components/ui/flex"
2521
import { Tag, TagButton } from "@/components/ui/tag"
2622

@@ -36,12 +32,6 @@ import externalTutorials from "@/data/externalTutorials.json"
3632

3733
import { DEFAULT_LOCALE } from "@/lib/constants"
3834

39-
import { useBreakpointValue } from "@/hooks/useBreakpointValue"
40-
41-
type LinkFlexProps = FlexProps & {
42-
href: string
43-
}
44-
4535
const FilterTag = forwardRef<
4636
HTMLButtonElement,
4737
{ isActive: boolean; name: string } & ButtonHTMLAttributes<HTMLButtonElement>
@@ -66,6 +56,10 @@ const Text = ({ className, ...props }: HTMLAttributes<HTMLHeadElement>) => (
6656
<p className={cn("mb-6", className)} {...props} />
6757
)
6858

59+
type LinkFlexProps = FlexProps & {
60+
href: string
61+
}
62+
6963
const LinkFlex = ({ href, children, ...props }: LinkFlexProps) => {
7064
return (
7165
<Flex asChild {...props}>
@@ -85,15 +79,11 @@ const published = (locale: string, published: string) => {
8579
) : null
8680
}
8781

88-
type TutorialPageProps = {
82+
type TutorialsListProps = {
8983
internalTutorials: ITutorial[]
90-
contentNotTranslated: boolean
9184
}
9285

93-
const TutorialPage = ({
94-
internalTutorials,
95-
contentNotTranslated,
96-
}: TutorialPageProps) => {
86+
const TutorialsList = ({ internalTutorials }: TutorialsListProps) => {
9787
const locale = useLocale()
9888
const effectiveLocale = internalTutorials.length > 0 ? locale : DEFAULT_LOCALE
9989
const filteredTutorialsByLang = useMemo(
@@ -111,7 +101,6 @@ const TutorialPage = ({
111101
[filteredTutorialsByLang]
112102
)
113103

114-
const [isModalOpen, setModalOpen] = useState(false)
115104
const [filteredTutorials, setFilteredTutorials] = useState(
116105
filteredTutorialsByLang
117106
)
@@ -152,66 +141,8 @@ const TutorialPage = ({
152141
setSelectedTags([...tempSelectedTags])
153142
}
154143

155-
const dir = contentNotTranslated ? "ltr" : "unset"
156-
157-
const modalSize = useBreakpointValue({ base: "xl", md: "md" } as const)
158144
return (
159-
<MainArticle
160-
className={`mx-auto my-0 mt-16 flex w-full flex-col items-center ${dir}`}
161-
>
162-
<h1 className="no-italic mb-4 text-center font-monospace text-[2rem] font-semibold uppercase leading-[1.4] max-sm:mx-4 max-sm:mt-4 sm:mb-[1.625rem]">
163-
<Translation id="page-developers-tutorials:page-tutorial-title" />
164-
</h1>
165-
<Text className="mb-4 text-center leading-xs text-body-medium">
166-
<Translation id="page-developers-tutorials:page-tutorial-subtitle" />
167-
</Text>
168-
169-
<Modal
170-
open={isModalOpen}
171-
onOpenChange={(open) => setModalOpen(open)}
172-
size={modalSize}
173-
contentProps={{ dir }}
174-
title={
175-
<Translation id="page-developers-tutorials:page-tutorial-submit-btn" />
176-
}
177-
>
178-
<Text>
179-
<Translation id="page-developers-tutorials:page-tutorial-listing-policy-intro" />
180-
</Text>
181-
<Flex className="flex-col gap-2 md:flex-row">
182-
<Flex className="w-full flex-col justify-between rounded-sm border border-border p-4">
183-
<b>
184-
<Translation id="page-developers-tutorials:page-tutorial-create-an-issue" />
185-
</b>
186-
<Text>
187-
<Translation id="page-developers-tutorials:page-tutorial-create-an-issue-desc" />
188-
</Text>
189-
<ButtonLink
190-
variant="outline"
191-
href="https://github.com/ethereum/ethereum-org-website/issues/new?assignees=&labels=Type%3A+Feature&template=suggest_tutorial.yaml&title="
192-
>
193-
<FaGithub />
194-
<Translation id="page-developers-tutorials:page-tutorial-raise-issue-btn" />
195-
</ButtonLink>
196-
</Flex>
197-
</Flex>
198-
</Modal>
199-
200-
<Button
201-
className="px-3 py-2 text-body"
202-
variant="outline"
203-
onClick={() => {
204-
setModalOpen(true)
205-
trackCustomEvent({
206-
eventCategory: "tutorials tags",
207-
eventAction: "click",
208-
eventName: "submit",
209-
})
210-
}}
211-
>
212-
<Translation id="page-developers-tutorials:page-tutorial-submit-btn" />
213-
</Button>
214-
145+
<>
215146
<div className="my-8 w-full shadow-table-box md:w-2/3">
216147
<Flex className="m-8 flex-col justify-center border-b border-border px-0 pb-4 pt-4 md:pb-8">
217148
<Flex className="mb-4 max-w-full flex-wrap items-center gap-2">
@@ -312,9 +243,8 @@ const TutorialPage = ({
312243
)
313244
})}
314245
</div>
315-
<FeedbackCard />
316-
</MainArticle>
246+
</>
317247
)
318248
}
319249

320-
export default TutorialPage
250+
export default TutorialsList

app/[locale]/developers/tutorials/page.tsx

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { pick } from "lodash"
2+
import dynamic from "next/dynamic"
23
import {
34
getMessages,
45
getTranslations,
@@ -7,20 +8,51 @@ import {
78

89
import { Lang } from "@/lib/types"
910

11+
import FeedbackCard from "@/components/FeedbackCard"
1012
import I18nProvider from "@/components/I18nProvider"
13+
import MainArticle from "@/components/MainArticle"
14+
import { Skeleton, SkeletonCardContent } from "@/components/ui/skeleton"
1115

1216
import { existsNamespace } from "@/lib/utils/existsNamespace"
1317
import { getTutorialsData } from "@/lib/utils/md"
1418
import { getMetadata } from "@/lib/utils/metadata"
1519
import { getRequiredNamespacesForPage } from "@/lib/utils/translations"
1620

17-
import Tutorials from "./_components/tutorials"
21+
const TutorialsList = dynamic(() => import("./_components/tutorials"), {
22+
ssr: false,
23+
loading: () => (
24+
<div className="mt-8 w-full md:w-2/3">
25+
<div className="grid w-full grid-cols-3 gap-2 px-8 pb-16 pt-12 sm:grid-cols-4 lg:gap-4 2xl:grid-cols-5">
26+
{Array.from({ length: 30 }).map((_, index) => (
27+
<Skeleton key={"tag" + index} className="h-8 rounded-full" />
28+
))}
29+
</div>
30+
{Array.from({ length: 5 }).map((_, index) => (
31+
<SkeletonCardContent key={"card" + index} className="p-8" />
32+
))}
33+
</div>
34+
),
35+
})
36+
37+
const TutorialSubmitModal = dynamic(() => import("./_components/modal"), {
38+
ssr: false,
39+
loading: () => (
40+
<div className="w-full max-w-40 rounded border p-3">
41+
<Skeleton className="h-5 w-full" />
42+
</div>
43+
),
44+
})
1845

1946
const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
2047
const { locale } = await params
2148

2249
setRequestLocale(locale)
2350

51+
const t = await getTranslations({
52+
locale,
53+
namespace: "page-developers-tutorials",
54+
})
55+
2456
// Get i18n messages
2557
const allMessages = await getMessages({ locale })
2658
const requiredNamespaces = getRequiredNamespacesForPage(
@@ -29,13 +61,29 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
2961
const messages = pick(allMessages, requiredNamespaces)
3062

3163
const contentNotTranslated = !existsNamespace(locale!, requiredNamespaces[2])
64+
const dir = contentNotTranslated ? "ltr" : "unset"
65+
66+
const internalTutorials = await getTutorialsData(locale)
3267

3368
return (
3469
<I18nProvider locale={locale} messages={messages}>
35-
<Tutorials
36-
internalTutorials={getTutorialsData(locale)}
37-
contentNotTranslated={contentNotTranslated}
38-
/>
70+
<MainArticle
71+
className="mx-auto my-0 mt-16 flex w-full flex-col items-center"
72+
dir={dir}
73+
>
74+
<h1 className="no-italic mb-4 text-center font-monospace text-[2rem] font-semibold uppercase leading-[1.4] max-sm:mx-4 max-sm:mt-4 sm:mb-[1.625rem]">
75+
{t("page-tutorial-title")}
76+
</h1>
77+
<p className="mb-4 text-center leading-xs text-body-medium">
78+
{t("page-tutorial-subtitle")}
79+
</p>
80+
81+
<TutorialSubmitModal dir={dir} />
82+
83+
<TutorialsList internalTutorials={internalTutorials} />
84+
85+
<FeedbackCard />
86+
</MainArticle>
3987
</I18nProvider>
4088
)
4189
}

0 commit comments

Comments
 (0)