Skip to content

Commit 0836e7a

Browse files
committed
[refactor] isolate Internationalization data with MobX-i18n 0.7 & React context
[optimize] use JWT to verify Cache API [optimize] reduce Dependency conflicts with Independent Configuration module [optimize] upgrade to Next-SSR-middleware 1.0 & other latest Upstream packages
1 parent d7b1d71 commit 0836e7a

27 files changed

+1157
-1005
lines changed

.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ NEXT_PUBLIC_SITE_SUMMARY = 全行业信息化转型专家
33
NEXT_PUBLIC_LOGO = /idea2app.svg
44

55
NEXT_PUBLIC_CACHE_HOST = https://cache.idea2.app
6+
CACHE_REPOSITORY = idea2app/OWS-cache
67

78
NEXT_PUBLIC_SENTRY_DSN = https://03e5d951172f411a04c1bab44022e22b@o4506471366852608.ingest.sentry.io/4506484563705856
89
SENTRY_ORG = idea2app

README.md

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,20 @@ You can check out [the Next.js GitHub repository][27] - your feedback and contri
6868

6969
| name | file | description |
7070
| :----------------------: | :----------: | :---------------------: |
71-
| `CRAWLER_TOKEN` | `.env.local` | Web hooks authorization |
72-
| `SENTRY_AUTH_TOKEN` | `.env.local` | [Official document][28] |
73-
| `SENTRY_ORG` | `.env` | [Official document][29] |
74-
| `SENTRY_PROJECT` | `.env` | [Official document][29] |
75-
| `NEXT_PUBLIC_SENTRY_DSN` | `.env` | [Official document][30] |
76-
| `GITHUB_TOKEN` | `.env.local` | [Official document][31] |
77-
| `LARK_APP_ID` | `.env.local` | [Official document][32] |
78-
| `LARK_APP_SECRET` | `.env.local` | [Official document][32] |
71+
| `JWT_SECRET` | `.env.local` | [API authorization][28] |
72+
| `SENTRY_AUTH_TOKEN` | `.env.local` | [Official document][29] |
73+
| `SENTRY_ORG` | `.env` | [Official document][30] |
74+
| `SENTRY_PROJECT` | `.env` | [Official document][30] |
75+
| `NEXT_PUBLIC_SENTRY_DSN` | `.env` | [Official document][31] |
76+
| `GITHUB_TOKEN` | `.env.local` | [Official document][32] |
77+
| `LARK_APP_ID` | `.env.local` | [Official document][33] |
78+
| `LARK_APP_SECRET` | `.env.local` | [Official document][33] |
7979

8080
### Vercel
8181

8282
The easiest way to deploy your Next.js app is to use the [Vercel Platform][13] from the creators of Next.js.
8383

84-
Check out our [Next.js deployment documentation][33] for more details.
84+
Check out our [Next.js deployment documentation][34] for more details.
8585

8686
### Docker
8787

@@ -110,16 +110,17 @@ pnpm container
110110
[18]: https://github.com/new?template_name=idea2app.github.io&template_owner=idea2app
111111
[19]: https://github.com/idea2app/idea2app.github.io/blob/34a68d5c3a21665c5971edff5aa7c208647d1566/.github/workflows/main.yml#L9-L11
112112
[20]: https://github.com/idea2app/idea2app.github.io/settings/secrets/actions
113-
[21]: https://github.com/kaiyuanshe/kaiyuanshe.github.io/blob/bb4675a56bf1d6b207231313da5ed0af7cf0ebd6/.github/workflows/pull-request.yml#L32-L56
113+
[21]: https://github.com/idea2app/Lark-Next-Bootstrap-ts/blob/363e023e5dd472c8ea53ec96eac25ec5122e667b/.github/workflows/Lark-notification.yml#L39
114114
[22]: https://github.com/idea2app/idea2app.github.io/issues/new/choose
115115
[23]: https://github.com/idea2app/idea2app.github.io/projects
116116
[24]: https://nextjs.org/docs/api-routes/introduction
117117
[25]: https://nextjs.org/docs
118118
[26]: https://nextjs.org/learn
119119
[27]: https://github.com/vercel/next.js/
120-
[28]: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#use-configuration-files-for-source-map-upload
121-
[29]: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#use-environment-variables
122-
[30]: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#create-initialization-config-files
123-
[31]: https://docs.github.com/en/rest/authentication/authenticating-to-the-rest-api#authenticating-with-a-personal-access-token
124-
[32]: https://open.larksuite.com/document/server-docs/getting-started/api-access-token/app-access-token-development-guide#95c7f5f5
125-
[33]: https://nextjs.org/docs/deployment
120+
[28]: https://github.com/auth0/node-jsonwebtoken?tab=readme-ov-file#jwtsignpayload-secretorprivatekey-options-callback
121+
[29]: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#use-configuration-files-for-source-map-upload
122+
[30]: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#use-environment-variables
123+
[31]: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#create-initialization-config-files
124+
[32]: https://docs.github.com/en/rest/authentication/authenticating-to-the-rest-api#authenticating-with-a-personal-access-token
125+
[33]: https://open.larksuite.com/document/server-docs/getting-started/api-access-token/app-access-token-development-guide#95c7f5f5
126+
[34]: https://nextjs.org/docs/deployment

components/Git/Card.tsx

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { Button, Chip } from '@mui/material';
22
import { GitRepository } from 'mobx-github';
33
import { observer } from 'mobx-react';
44
import Link from 'next/link';
5-
import { FC } from 'react';
5+
import { FC, useContext } from 'react';
66

7-
import { i18n } from '../../models/Translation';
7+
import { I18nContext } from '../../models/Translation';
88

99
export interface GitCardProps
1010
extends Pick<GitRepository, 'full_name' | 'html_url' | 'languages'>,
@@ -13,39 +13,43 @@ export interface GitCardProps
1313
}
1414

1515
export const GitCard: FC<GitCardProps> = observer(
16-
({ className = '', full_name, html_url, topics = [], description, homepage }) => (
17-
<li
18-
className={`${className} grid grid-cols-1 grid-rows-10 gap-2 rounded-2xl border p-4 elevation-1 hover:elevation-8 dark:border-0`}
19-
>
20-
<h2 className="row-span-2 text-lg">
21-
<a target="_blank" href={html_url} rel="noreferrer">
22-
{full_name}
23-
</a>
24-
</h2>
16+
({ className = '', full_name, html_url, topics = [], description, homepage }) => {
17+
const { t } = useContext(I18nContext);
2518

26-
<nav className="row-span-3 flex flex-row flex-wrap gap-2">
27-
{topics.map(topic => (
28-
<Chip
29-
key={topic}
30-
size="small"
31-
component="a"
32-
target="_blank"
33-
href={`https://github.com/topics/${topic}`}
34-
label={topic}
35-
/>
36-
))}
37-
</nav>
19+
return (
20+
<li
21+
className={`${className} elevation-1 hover:elevation-8 grid grid-cols-1 grid-rows-10 gap-2 rounded-2xl border p-4 dark:border-0`}
22+
>
23+
<h2 className="row-span-2 text-lg">
24+
<a target="_blank" href={html_url} rel="noreferrer">
25+
{full_name}
26+
</a>
27+
</h2>
3828

39-
<p className="row-span-3 text-sm">{description}</p>
29+
<nav className="row-span-3 flex flex-row flex-wrap gap-2">
30+
{topics.map(topic => (
31+
<Chip
32+
key={topic}
33+
size="small"
34+
component="a"
35+
target="_blank"
36+
href={`https://github.com/topics/${topic}`}
37+
label={topic}
38+
/>
39+
))}
40+
</nav>
4041

41-
<Button
42-
className="row-span-2 place-self-center"
43-
component={Link}
44-
target="_blank"
45-
href={homepage ?? html_url}
46-
>
47-
{i18n.t('home_page')}
48-
</Button>
49-
</li>
50-
),
42+
<p className="row-span-3 text-sm">{description}</p>
43+
44+
<Button
45+
className="row-span-2 place-self-center"
46+
component={Link}
47+
target="_blank"
48+
href={homepage ?? html_url}
49+
>
50+
{t('home_page')}
51+
</Button>
52+
</li>
53+
);
54+
},
5155
);

components/Layout/MainNavigator.tsx

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,51 @@
11
import { AppBar, Drawer, IconButton, Menu, MenuItem, PopoverProps, Toolbar } from '@mui/material';
2-
import { observable } from 'mobx';
2+
import { computed, observable } from 'mobx';
33
import { observer } from 'mobx-react';
4+
import { ObservedComponent, observePropsState } from 'mobx-react-helper';
45
import Link from 'next/link';
56
import { Component } from 'react';
67

7-
import { i18n, LanguageName, t } from '../../models/Translation';
8+
import { i18n, I18nContext, LanguageName } from '../../models/Translation';
89
import { SymbolIcon } from '../Icon';
910
import { ColorModeIconDropdown } from './ColorModeDropdown';
1011
import { BrandLogo, GithubIcon } from './Svg';
1112

12-
export const mainNavLinks = () => [
13-
{ title: t('latest_projects'), href: '/project' },
14-
{ title: 'GitHub-reward', href: '/project/reward/issue', target: '_top' },
15-
{ title: t('member'), href: '/member' },
16-
{ title: t('open_source_project'), href: '/open-source' },
17-
];
13+
export interface MainNavigator extends ObservedComponent<{}, typeof i18n> {}
1814

1915
@observer
16+
@observePropsState
2017
export class MainNavigator extends Component {
18+
static contextType = I18nContext;
19+
2120
@observable accessor menuExpand = false;
2221
@observable accessor menuAnchor: PopoverProps['anchorEl'] = null;
2322

23+
@computed
24+
get links() {
25+
const { t } = this.observedContext!;
26+
27+
return [
28+
{ title: t('latest_projects'), href: '/project' },
29+
{ title: 'GitHub-reward', href: '/project/reward/issue', target: '_top' },
30+
{ title: t('member'), href: '/member' },
31+
{ title: t('open_source_project'), href: '/open-source' },
32+
];
33+
}
34+
2435
switchI18n = (key: string) => {
25-
i18n.changeLanguage(key as keyof typeof LanguageName);
36+
this.observedContext!.loadLanguages(key as keyof typeof LanguageName);
2637
this.menuAnchor = null;
2738
};
2839

2940
renderLinks = () =>
30-
mainNavLinks().map(({ title, href, target }) => (
41+
this.links.map(({ title, href, target }) => (
3142
<Link key={title} className="py-1" href={href} target={target}>
3243
{title}
3344
</Link>
3445
));
3546

3647
renderI18nSwitch = () => {
37-
const { currentLanguage } = i18n,
48+
const { currentLanguage } = this.observedContext!,
3849
{ menuAnchor } = this;
3950

4051
return (
@@ -50,12 +61,7 @@ export class MainNavigator extends Component {
5061
<Menu
5162
anchorEl={menuAnchor}
5263
id="i18n-menu"
53-
slotProps={{
54-
paper: {
55-
variant: 'outlined',
56-
sx: { my: '4px' },
57-
},
58-
}}
64+
slotProps={{ paper: { variant: 'outlined', sx: { my: '4px' } } }}
5965
open={Boolean(menuAnchor)}
6066
onClose={() => (this.menuAnchor = null)}
6167
>
@@ -89,7 +95,7 @@ export class MainNavigator extends Component {
8995
variant="temporary"
9096
anchor="top"
9197
ModalProps={{ keepMounted: true }}
92-
PaperProps={{ className: 'w-full bg-transparent shadow-none bg-none' }}
98+
slotProps={{ paper: { className: 'w-full bg-transparent shadow-none bg-none' } }}
9399
open={this.menuExpand}
94100
onClose={() => (this.menuExpand = false)}
95101
>

components/Layout/ScrollListPage.tsx

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { DataObject, Filter, ListModel } from 'mobx-restful';
2-
import { FC, HTMLAttributes } from 'react';
2+
import { FC, HTMLAttributes, useContext } from 'react';
33

4-
import { i18n } from '../../models/Translation';
4+
import { I18nContext } from '../../models/Translation';
55
import { PageHead } from '../PageHead';
66
import { ScrollList } from '../ScrollList';
77

@@ -27,19 +27,23 @@ export const ScrollListPage = <D extends DataObject, F extends Filter<D> = Filte
2727
header,
2828
Layout,
2929
...rest
30-
}: ScrollListPageProps<D, F>) => (
31-
<div className={`container mx-auto max-w-(--breakpoint-xl) px-4 pt-16 pb-6 ${className}`}>
32-
<PageHead title={title} />
33-
<h1 className="my-8 text-4xl">{header}</h1>
30+
}: ScrollListPageProps<D, F>) => {
31+
const i18n = useContext(I18nContext);
3432

35-
{scrollList ? (
36-
<ScrollList
37-
translator={i18n}
38-
renderList={allItems => <Layout defaultData={allItems} />}
39-
{...rest}
40-
/>
41-
) : (
42-
children
43-
)}
44-
</div>
45-
);
33+
return (
34+
<div className={`container mx-auto max-w-(--breakpoint-xl) px-4 pt-16 pb-6 ${className}`}>
35+
<PageHead title={title} />
36+
<h1 className="my-8 text-4xl">{header}</h1>
37+
38+
{scrollList ? (
39+
<ScrollList
40+
translator={i18n}
41+
renderList={allItems => <Layout defaultData={allItems} />}
42+
{...rest}
43+
/>
44+
) : (
45+
children
46+
)}
47+
</div>
48+
);
49+
};

components/Layout/Section.tsx

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,34 @@
11
import { Button } from '@mui/material';
22
import { observer } from 'mobx-react';
33
import Link from 'next/link';
4-
import { FC, PropsWithChildren } from 'react';
4+
import { FC, PropsWithChildren, useContext } from 'react';
55

6-
import { t } from '../../models/Translation';
6+
import { I18nContext } from '../../models/Translation';
77

88
export type SectionProps = PropsWithChildren<
99
Partial<Record<'id' | 'title' | 'link' | 'className', string>>
1010
>;
1111

1212
export const Section: FC<SectionProps> = observer(
13-
({ id, title, children, link, className = '' }) => (
14-
<section className={`mx-auto flex max-w-(--breakpoint-xl) flex-col gap-6 py-8 ${className}`}>
15-
<h2 className="text-center" id={id}>
16-
{title}
17-
</h2>
13+
({ id, title, children, link, className = '' }) => {
14+
const { t } = useContext(I18nContext);
1815

19-
{children}
16+
return (
17+
<section className={`mx-auto flex max-w-(--breakpoint-xl) flex-col gap-6 py-8 ${className}`}>
18+
<h2 className="text-center" id={id}>
19+
{title}
20+
</h2>
2021

21-
{link && (
22-
<footer className="text-center">
23-
<Button component={Link} href={link} aria-label={`load more ${title}`}>
24-
{t('load_more')}
25-
</Button>
26-
</footer>
27-
)}
28-
</section>
29-
),
22+
{children}
23+
24+
{link && (
25+
<footer className="text-center">
26+
<Button component={Link} href={link} aria-label={`load more ${title}`}>
27+
{t('load_more')}
28+
</Button>
29+
</footer>
30+
)}
31+
</section>
32+
);
33+
},
3034
);

components/NotFoundCard.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
/* eslint-disable @next/next/no-sync-scripts */
22
import { ErrorProps } from 'next/error';
3-
import { FC } from 'react';
3+
import { FC, useContext } from 'react';
44

5-
import { i18n } from '../models/Translation';
5+
import { I18nContext } from '../models/Translation';
66

7-
export const NotFoundCard: FC<ErrorProps> = ({ title }) =>
8-
i18n.currentLanguage.startsWith('zh') ? (
7+
export const NotFoundCard: FC<ErrorProps> = ({ title }) => {
8+
const { currentLanguage } = useContext(I18nContext);
9+
10+
return currentLanguage.startsWith('zh') ? (
911
<script
1012
src="//cdn.dnpw.org/404/v1.min.js"
1113
// @ts-expect-error https://www.dnpw.org/cn/pa-notfound.html
@@ -15,7 +17,8 @@ export const NotFoundCard: FC<ErrorProps> = ({ title }) =>
1517
/>
1618
) : (
1719
<iframe
18-
className="w-100 vh-100 border-0"
20+
className="vh-100 w-100 border-0"
1921
src="https://notfound-static.fwebservices.be/en/404?key=66abb751ed312"
2022
/>
2123
);
24+
};

models/Base.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ import MIME from 'mime';
33
import { githubClient } from 'mobx-github';
44
import { TableCellValue, TableCellMedia, TableCellAttachment } from 'mobx-lark';
55

6-
import { API_Host, GithubToken, isServer } from './configuration';
6+
import { API_Host, GITHUB_TOKEN, isServer } from './configuration';
77

88
if (!isServer()) githubClient.baseURI = `${API_Host}/api/GitHub/`;
99

1010
githubClient.use(({ request }, next) => {
11-
if (GithubToken)
11+
if (GITHUB_TOKEN)
1212
request.headers = {
13-
Authorization: `Bearer ${GithubToken}`,
13+
Authorization: `Bearer ${GITHUB_TOKEN}`,
1414
...request.headers,
1515
};
1616
return next();

0 commit comments

Comments
 (0)