Skip to content

Commit c9f70c8

Browse files
authored
Convert to NextJS app (#350)
* Convert to nextjs app This is a simple one page application that fetches data from GH in a useEffect. We can leverage a server function to handle the search and caching and then SSR the page content. This change just converts the app as is to use Next. The next commits restructure the app to take advantage of server rendering. * Convert glamor to css modules Glamor is client-only which means we'd have to add the 'use client' directive everywhere that we style. Let's instead switch to simple CSS modules to enable SSR. * Move GH search request to server Instead of rendering empty and then searching in an effect, we can move the search request to the server to SSR the complete site. * Update dependencies and fix eslint Update to latest while we're here and make sure linting works with next integration * Update UI styling Add some polish to the UI while we're here updating everything else. * Add error handling for failed GH search * Remove sort selector weight change * Fix deployment
1 parent 7661529 commit c9f70c8

30 files changed

+2884
-25402
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ yarn-error.log
88

99
.temp
1010
.env*
11-
!.env.sample
11+
!.env.sample
12+
13+
build/

langs/langs.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@
2424
{ "code": "ml", "name": "മലയാളം", "enName": "Malayalam" },
2525
{ "code": "mn", "name": "Монгол хэл", "enName": "Mongolian" },
2626
{ "code": "pl", "name": "Polski", "enName": "Polish" },
27-
{ "code": "pt-br", "name": "Português do Brasil", "enName": "Portuguese (Brazil)" },
27+
{
28+
"code": "pt-br",
29+
"name": "Português do Brasil",
30+
"enName": "Portuguese (Brazil)"
31+
},
2832
{ "code": "ru", "name": "Русский", "enName": "Russian" },
2933
{ "code": "si", "name": "සිංහල", "enName": "Sinhala" },
3034
{ "code": "sr", "name": "Srpski", "enName": "Serbian" },

website/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,6 @@
1616

1717
# Copied on build
1818
src/langs.json
19+
20+
.next/
21+
out/
File renamed without changes.

website/app/layout.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import 'what-input'
2+
import '../src/reset.css'
3+
import '../src/box-sizing.css'
4+
import '../src/a11y.css'
5+
6+
export const metadata = {
7+
title: 'Is React Translated Yet?',
8+
description: 'The global React community is translating react.dev into multiple languages',
9+
}
10+
11+
export default function RootLayout({ children }) {
12+
return (
13+
<html lang="en">
14+
<head>
15+
<link rel="icon" href="/app/favicon.ico" />
16+
</head>
17+
<body>{children}</body>
18+
</html>
19+
)
20+
}

website/app/page.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import App from '../src/App'
2+
import langs from '../src/langs.json'
3+
import { graphql } from '@octokit/graphql'
4+
import fromPairs from 'lodash/fromPairs'
5+
6+
function getLangProgress(lang, issue) {
7+
const { body, createdAt, lastEditedAt = createdAt, ...issueProps } = issue
8+
let coreCompletion = 0
9+
let otherCompletion = 0
10+
body.split(/^##\s+/gm).forEach((section) => {
11+
const [heading, ...content] = section.split('\n')
12+
const items = content.filter((line) => {
13+
return /[-*] *\[[ x]\]/.test(line)
14+
})
15+
const finishedItems = items.filter((line) => /[-*] \[x\]/.test(line))
16+
if (/MAIN_CONTENT/.test(heading)) {
17+
coreCompletion = finishedItems.length / items.length
18+
} else if (/SECONDARY_CONTENT/.test(heading)) {
19+
otherCompletion = finishedItems.length / items.length
20+
}
21+
})
22+
return {
23+
...lang,
24+
...issueProps,
25+
createdAt,
26+
lastEditedAt,
27+
coreCompletion,
28+
otherCompletion,
29+
}
30+
}
31+
32+
async function getProgressList(langs) {
33+
const { search } = await graphql(
34+
`
35+
query ($limit: Int!) {
36+
search(
37+
type: ISSUE
38+
query: "org:reactjs Translation Progress in:title is:open"
39+
first: $limit
40+
) {
41+
nodes {
42+
... on Issue {
43+
title
44+
body
45+
createdAt
46+
lastEditedAt
47+
number
48+
repository {
49+
name
50+
}
51+
}
52+
}
53+
}
54+
}
55+
`,
56+
{
57+
headers: {
58+
authorization: `token ${process.env.REACT_APP_GITHUB_AUTH_TOKEN}`,
59+
},
60+
limit: langs.length + 15,
61+
},
62+
)
63+
64+
const issuesMap = fromPairs(
65+
search.nodes
66+
.filter((issue) => !!issue && issue.repository)
67+
.map((issue) => [issue.repository.name.toLowerCase(), issue]),
68+
)
69+
70+
return langs
71+
.map((lang) => {
72+
const issue = issuesMap[`${lang.code.toLowerCase()}.react.dev`]
73+
return issue ? getLangProgress(lang, issue) : null
74+
})
75+
.filter(Boolean)
76+
}
77+
78+
export default async function HomePage() {
79+
let progressList
80+
try {
81+
progressList = await getProgressList(langs)
82+
} catch (e) {
83+
progressList = langs.map(lang => ({
84+
...lang,
85+
coreCompletion: undefined,
86+
otherCompletion: undefined,
87+
createdAt: undefined,
88+
lastEditedAt: undefined,
89+
}))
90+
}
91+
return <App progressList={progressList} />
92+
}

website/eslint.config.mjs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { dirname } from 'path'
2+
import { fileURLToPath } from 'url'
3+
import { FlatCompat } from '@eslint/eslintrc'
4+
5+
const __filename = fileURLToPath(import.meta.url)
6+
const __dirname = dirname(__filename)
7+
8+
const compat = new FlatCompat({
9+
baseDirectory: __dirname,
10+
})
11+
12+
const eslintConfig = [
13+
...compat.extends('next'),
14+
{
15+
ignores: [
16+
'node_modules/**',
17+
'.next/**',
18+
'out/**',
19+
'build/**',
20+
'next-env.d.ts',
21+
],
22+
},
23+
]
24+
25+
export default eslintConfig

website/next.config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/** @type {import('next').NextConfig} */
2+
const nextConfig = {
3+
}
4+
5+
module.exports = nextConfig

0 commit comments

Comments
 (0)