Skip to content

Commit a47e0c6

Browse files
authored
Merge pull request #159 from ethereum/tutorialsPageMigration
/developers/tutorials page migration
2 parents e7bb9b1 + 91c5225 commit a47e0c6

File tree

4 files changed

+633
-0
lines changed

4 files changed

+633
-0
lines changed

src/lib/utils/md.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,22 @@ import fs from "fs"
22
import { extname, join } from "path"
33

44
import matter from "gray-matter"
5+
import readingTime from "reading-time"
56

67
import type { Frontmatter } from "@/lib/types"
78
import type { MdPageContent } from "@/lib/interfaces"
89

10+
import { Skill } from "@/components/TutorialMetadata"
11+
12+
import { dateToString } from "@/lib/utils/date"
913
import { getFallbackEnglishPath, removeEnglishPrefix } from "@/lib/utils/i18n"
1014

1115
import { CONTENT_DIR, DEFAULT_LOCALE, LOCALES_CODES } from "@/lib/constants"
1216

1317
import { toPosixPath } from "./relativePath"
1418

19+
import { ITutorial } from "@/pages/developers/tutorials"
20+
1521
const CURRENT_CONTENT_DIR = join(process.cwd(), CONTENT_DIR)
1622

1723
const getPostSlugs = (dir: string, files: string[] = []) => {
@@ -340,3 +346,34 @@ export const getContent = (dir: string) => {
340346

341347
return content
342348
}
349+
350+
export const getTutorialsData = (locale: string): ITutorial[] => {
351+
const fullPath = join(CURRENT_CONTENT_DIR, locale !== 'en' ? `translations/${locale!}` : '', 'developers/tutorials')
352+
let tutorialData: ITutorial[] = []
353+
354+
if (fs.existsSync(fullPath)) {
355+
const languageTutorialFiles = fs.readdirSync(fullPath)
356+
357+
tutorialData = languageTutorialFiles.map((dir) => {
358+
const filePath = join(CURRENT_CONTENT_DIR, locale !== 'en' ? `translations/${locale!}` : '', 'developers/tutorials', dir, 'index.md')
359+
const fileContents = fs.readFileSync(filePath, "utf8")
360+
const { data, content } = matter(fileContents)
361+
const frontmatter = data as Frontmatter
362+
363+
return {
364+
to: join(`/${locale}/developers/tutorials`, dir),
365+
title: frontmatter.title,
366+
description: frontmatter.description,
367+
author: frontmatter.author || '',
368+
tags: frontmatter.tags,
369+
skill: frontmatter.skill as Skill,
370+
timeToRead: Math.round(readingTime(content).minutes),
371+
published: dateToString(frontmatter.published),
372+
lang: frontmatter.lang,
373+
isExternal: false,
374+
}
375+
})
376+
}
377+
378+
return tutorialData
379+
}

src/lib/utils/translations.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ const getRequiredNamespacesForPath = (path: string) => {
9494
requiredNamespaces = [...requiredNamespaces, "page-developers-index", "page-developers-learning-tools"]
9595
}
9696

97+
if (path.startsWith("/developers/tutorials")) {
98+
requiredNamespaces = [...requiredNamespaces, "page-developers-tutorials"]
99+
}
100+
97101
if (path.startsWith("/developers/docs/scaling")) {
98102
requiredNamespaces = [...requiredNamespaces, "page-layer-2"]
99103
}

src/lib/utils/tutorial.ts

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { Lang } from "@/lib/types"
2+
3+
import { Skill } from "@/components/TutorialMetadata"
4+
5+
import { IExternalTutorial, ITutorial } from "@/pages/developers/tutorials"
6+
7+
// Take all tutorials, and return a list of tutorials for a specific locale
8+
export const filterTutorialsByLang = (
9+
internalTutorials: any,
10+
externalTutorials: Array<IExternalTutorial>,
11+
locale: Lang
12+
): Array<ITutorial> => {
13+
const internalTutorialsMap = internalTutorials.map((tutorial) => {
14+
const lang = tutorial?.lang || "en"
15+
16+
return {
17+
to: tutorial.to || "",
18+
title: tutorial?.title || "",
19+
description: tutorial?.description || "",
20+
author: tutorial?.author || "",
21+
tags: tutorial?.tags?.map((tag) =>
22+
(tag || "").toLowerCase().trim()
23+
),
24+
skill: tutorial?.skill as Skill,
25+
timeToRead: tutorial?.timeToRead,
26+
published: tutorial?.published,
27+
lang: tutorial?.lang,
28+
isExternal: false,
29+
}
30+
})
31+
32+
const externalTutorialsMap = externalTutorials.map<ITutorial>(
33+
(tutorial: IExternalTutorial) => ({
34+
to: tutorial.url,
35+
title: tutorial.title,
36+
description: tutorial.description,
37+
author: tutorial.author,
38+
tags: tutorial.tags.map((tag) => tag.toLowerCase().trim()),
39+
skill: tutorial.skillLevel as Skill,
40+
timeToRead: Number(tutorial.timeToRead),
41+
published: new Date(tutorial.publishDate).toISOString(),
42+
lang: tutorial.lang || "en",
43+
isExternal: true,
44+
})
45+
)
46+
47+
const allTutorials: Array<ITutorial> = [
48+
...externalTutorialsMap,
49+
...internalTutorialsMap,
50+
]
51+
52+
const filteredTutorials = allTutorials
53+
.filter((tutorial) => tutorial.lang === locale)
54+
.sort((a, b) => {
55+
if (a.published && b.published) {
56+
return new Date(b.published).getTime() - new Date(a.published).getTime()
57+
}
58+
// Dont order if no published is present
59+
return 0
60+
})
61+
62+
return filteredTutorials
63+
}
64+
65+
export const getSortedTutorialTagsForLang = (
66+
filteredTutorialsByLang: Array<ITutorial> = []
67+
) => {
68+
const allTags = filteredTutorialsByLang.reduce<Array<string>>(
69+
(tags, tutorial) => {
70+
return [...tags, ...(tutorial.tags || [])]
71+
},
72+
[]
73+
)
74+
75+
const reducedTags = allTags.reduce((acc, tag) => {
76+
if (acc[tag]) {
77+
acc[tag] = acc[tag] + 1
78+
} else {
79+
acc[tag] = 1
80+
}
81+
return acc
82+
}, {})
83+
84+
const sortedTags = Object.keys(reducedTags)
85+
.sort()
86+
.reduce((obj, key) => {
87+
obj[key] = reducedTags[key]
88+
return obj
89+
}, {})
90+
91+
return sortedTags
92+
}

0 commit comments

Comments
 (0)