Skip to content

Commit a1057c2

Browse files
committed
[optimize] simplify JSX structure & Data filter of GitHub-based Markdown Wiki pages
1 parent 35e585b commit a1057c2

File tree

11 files changed

+100
-101
lines changed

11 files changed

+100
-101
lines changed

components/Layout/ContentTree.tsx

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,19 @@ import { Badge } from 'react-bootstrap';
44

55
import { XContent } from '../../models/Wiki';
66

7-
interface ContentTreeProps {
7+
export interface ContentTreeProps {
88
nodes: XContent[];
99
basePath: string;
1010
level?: number;
1111
metaKey?: string;
1212
}
1313

14-
export const ContentTree: FC<ContentTreeProps> = ({ nodes, basePath, level = 0, metaKey = '主题分类' }) => (
14+
export const ContentTree: FC<ContentTreeProps> = ({
15+
nodes,
16+
basePath,
17+
level = 0,
18+
metaKey = 'category',
19+
}) => (
1520
<ol className={level === 0 ? 'list-unstyled' : ''}>
1621
{nodes.map(({ path, name, type, meta, children }) => (
1722
<li key={path} className={level > 0 ? 'ms-3' : ''}>
@@ -26,13 +31,20 @@ export const ContentTree: FC<ContentTreeProps> = ({ nodes, basePath, level = 0,
2631
)}
2732
</Link>
2833
) : (
29-
<details>
30-
<summary className="h4">{name}</summary>
34+
children?.[0] && (
35+
<details>
36+
<summary className="h4">{name}</summary>
3137

32-
<ContentTree nodes={children || []} basePath={basePath} level={level + 1} metaKey={metaKey} />
33-
</details>
38+
<ContentTree
39+
nodes={children}
40+
basePath={basePath}
41+
level={level + 1}
42+
metaKey={metaKey}
43+
/>
44+
</details>
45+
)
3446
)}
3547
</li>
3648
))}
3749
</ol>
38-
);
50+
);

components/Navigator/MainNavigator.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ const topNavBarMenu = ({ t }: typeof i18n): MenuItem[] => [
6060
subs: [
6161
{ href: '/wiki', title: t('wiki') },
6262
{ href: '/policy', title: t('policy') },
63-
{ href: '/recipes', title: t('recipes') },
63+
{ href: '/recipe', title: t('recipe') },
6464
],
6565
},
6666
];

next.config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ const rewrites: NextConfig['rewrites'] = async () => ({
3838
source: '/proxy/geo.datav.aliyun.com/:path*',
3939
destination: 'https://geo.datav.aliyun.com/:path*',
4040
},
41+
{
42+
source: '/recipe/images/:path*',
43+
destination: 'https://raw.githubusercontent.com/Gar-b-age/CookLikeHOC/main/images/:path*',
44+
},
4145
],
4246
afterFiles: [],
4347
});

pages/api/core.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'core-js/full/array/from-async';
22

33
import { Context, Middleware } from 'koa';
44
import { HTTPError } from 'koajax';
5+
import { Content } from 'mobx-github';
56
import { DataObject } from 'mobx-restful';
67
import { KoaOption, withKoa } from 'next-ssr-middleware';
78
import Path from 'path';
@@ -123,3 +124,17 @@ export function* traverseTree<K extends string, N extends TreeNode<K>>(
123124
yield* traverseTree(node as N, key);
124125
}
125126
}
127+
128+
export const filterMarkdownFiles = (nodes: Content[]) =>
129+
nodes
130+
.filter(
131+
({ path, type, name }) =>
132+
!path.startsWith('.') &&
133+
!name.startsWith('.') &&
134+
(type !== 'file' || MD_pattern.test(name)),
135+
)
136+
.map(({ content, ...rest }) => {
137+
const { meta, markdown } = content ? splitFrontMatter(content) : {};
138+
139+
return { ...rest, content: markdown, meta };
140+
});

pages/policy/[...slug].tsx

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -67,40 +67,29 @@ const WikiPage: FC<XContent> = observer(({ name, path, parent_path, content, met
6767
<header className="mb-4">
6868
<h1>{name}</h1>
6969

70-
{meta && (
71-
<div className="d-flex flex-wrap align-items-center gap-3 mb-3">
72-
<BadgeBar
73-
list={[
74-
meta['主题分类'] && { text: meta['主题分类'], color: 'primary' },
75-
meta['发文机构'] && { text: meta['发文机构'], color: 'secondary' },
76-
meta['有效性'] && {
77-
text: meta['有效性'],
78-
color: meta['有效性'] === '现行有效' ? 'success' : 'warning'
79-
}
80-
].filter(Boolean) as Array<{ text: string; color?: string }>}
81-
/>
82-
</div>
83-
)}
70+
{meta && <BadgeBar list={Object.values(meta).map(text => ({ text }))} />}
8471

8572
<div className="d-flex justify-content-between align-items-center text-muted small mb-3">
86-
<div>
73+
<dl>
8774
{meta?.['成文日期'] && (
88-
<span>
89-
{t('creation_date')}: {meta['成文日期']}
90-
</span>
75+
<>
76+
<dt>{t('creation_date')}:</dt>
77+
<dd>{meta['成文日期']}</dd>
78+
</>
9179
)}
9280
{meta?.['发布日期'] && meta['发布日期'] !== meta['成文日期'] && (
93-
<span className="ms-3">
94-
{t('publication_date')}: {meta['发布日期']}
95-
</span>
81+
<>
82+
<dt>{t('publication_date')}:</dt>
83+
<dd>{meta['发布日期']}</dd>
84+
</>
9685
)}
97-
</div>
86+
</dl>
9887

9988
<div className="d-flex gap-2">
10089
<Button
10190
variant="outline-primary"
10291
size="sm"
103-
href={`https://github.com/fpsig/open-source-policy/blob/main/China/政策/${path}`}
92+
href={`https://github.com/fpsig/open-source-policy/edit/main/China/政策/${path}`}
10493
target="_blank"
10594
rel="noopener noreferrer"
10695
>

pages/policy/index.tsx

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,10 @@ import { ContentTree } from '../../components/Layout/ContentTree';
88
import { PageHead } from '../../components/Layout/PageHead';
99
import { I18nContext } from '../../models/Translation';
1010
import { policyContentStore, XContent } from '../../models/Wiki';
11-
import { MD_pattern, splitFrontMatter } from '../api/core';
11+
import { filterMarkdownFiles } from '../api/core';
1212

1313
export const getStaticProps: GetStaticProps<{ nodes: XContent[] }> = async () => {
14-
const nodes = (await policyContentStore.getAll())
15-
.filter(({ type, name }) => type !== 'file' || MD_pattern.test(name))
16-
.map(({ content, ...rest }) => {
17-
const { meta, markdown } = content ? splitFrontMatter(content) : {};
18-
19-
return { ...rest, content: markdown, meta };
20-
});
14+
const nodes = filterMarkdownFiles(await policyContentStore.getAll());
2115

2216
return {
2317
props: JSON.parse(JSON.stringify({ nodes })),
@@ -47,8 +41,8 @@ const WikiIndexPage: FC<{ nodes: XContent[] }> = observer(({ nodes }) => {
4741
</hgroup>
4842

4943
{nodes[0] ? (
50-
<ContentTree
51-
nodes={treeFrom(nodes, 'path', 'parent_path', 'children')}
44+
<ContentTree
45+
nodes={treeFrom(nodes, 'path', 'parent_path', 'children')}
5246
basePath="/policy"
5347
metaKey="主题分类"
5448
/>

pages/recipes/[...slug].tsx renamed to pages/recipe/[...slug].tsx

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const getStaticPaths: GetStaticPaths<RecipePageParams> = async () => {
2020
const nodes = await recipeContentStore.getAll();
2121

2222
const paths = nodes
23-
.filter(({ type }) => type === 'file')
23+
.filter(({ type, name }) => type === 'file' && !name.startsWith('.'))
2424
.map(({ path }) => ({ params: { slug: path.split('/') } }));
2525

2626
return { paths, fallback: 'blocking' };
@@ -49,7 +49,7 @@ const RecipePage: FC<XContent> = observer(({ name, path, parent_path, content, m
4949
<PageHead title={name} />
5050

5151
<Breadcrumb className="mb-4">
52-
<Breadcrumb.Item href="/recipes">{t('recipes')}</Breadcrumb.Item>
52+
<Breadcrumb.Item href="/recipe">{t('recipe')}</Breadcrumb.Item>
5353

5454
{parent_path?.split('/').map((segment, index, array) => {
5555
const breadcrumbPath = array.slice(0, index + 1).join('/');
@@ -67,37 +67,29 @@ const RecipePage: FC<XContent> = observer(({ name, path, parent_path, content, m
6767
<header className="mb-4">
6868
<h1>{name}</h1>
6969

70-
{meta && (
71-
<div className="d-flex flex-wrap align-items-center gap-3 mb-3">
72-
<BadgeBar
73-
list={[
74-
meta['category'] && { text: meta['category'], color: 'primary' },
75-
meta['difficulty'] && { text: meta['difficulty'], color: 'secondary' },
76-
meta['time'] && { text: meta['time'], color: 'success' }
77-
].filter(Boolean) as Array<{ text: string; color?: string }>}
78-
/>
79-
</div>
80-
)}
70+
{meta && <BadgeBar list={Object.values(meta).map(text => ({ text }))} />}
8171

8272
<div className="d-flex justify-content-between align-items-center text-muted small mb-3">
83-
<div>
73+
<dl>
8474
{meta?.['servings'] && (
85-
<span>
86-
{t('servings')}: {meta['servings']}
87-
</span>
75+
<>
76+
<dt>{t('servings')}:</dt>
77+
<dd>{meta['servings']}</dd>
78+
</>
8879
)}
89-
{meta?.['prep_time'] && (
90-
<span className="ms-3">
91-
{t('prep_time')}: {meta['prep_time']}
92-
</span>
80+
{meta?.['preparation_time'] && (
81+
<>
82+
<dt>{t('preparation_time')}:</dt>
83+
<dd>{meta['preparation_time']}</dd>
84+
</>
9385
)}
94-
</div>
86+
</dl>
9587

9688
<div className="d-flex gap-2">
9789
<Button
9890
variant="outline-primary"
9991
size="sm"
100-
href={`https://github.com/Gar-b-age/CookLikeHOC/blob/main/${path}`}
92+
href={`https://github.com/Gar-b-age/CookLikeHOC/edit/main/${path}`}
10193
target="_blank"
10294
rel="noopener noreferrer"
10395
>
@@ -140,4 +132,4 @@ const RecipePage: FC<XContent> = observer(({ name, path, parent_path, content, m
140132
);
141133
});
142134

143-
export default RecipePage;
135+
export default RecipePage;
Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
11
import { observer } from 'mobx-react';
22
import { GetStaticProps } from 'next';
33
import React, { FC, useContext } from 'react';
4-
import { Button, Card, Container } from 'react-bootstrap';
4+
import { Alert, Button, Card, Container } from 'react-bootstrap';
55
import { treeFrom } from 'web-utility';
66

77
import { ContentTree } from '../../components/Layout/ContentTree';
88
import { PageHead } from '../../components/Layout/PageHead';
99
import { I18nContext } from '../../models/Translation';
1010
import { recipeContentStore, XContent } from '../../models/Wiki';
11-
import { MD_pattern, splitFrontMatter } from '../api/core';
11+
import { filterMarkdownFiles } from '../api/core';
1212

1313
export const getStaticProps: GetStaticProps<{ nodes: XContent[] }> = async () => {
14-
const nodes = (await recipeContentStore.getAll())
15-
.filter(({ type, name }) => type !== 'file' || MD_pattern.test(name))
16-
.map(({ content, ...rest }) => {
17-
const { meta, markdown } = content ? splitFrontMatter(content) : {};
18-
19-
return { ...rest, content: markdown, meta };
20-
});
14+
const nodes = filterMarkdownFiles(await recipeContentStore.getAll());
2115

2216
return {
2317
props: JSON.parse(JSON.stringify({ nodes })),
@@ -30,11 +24,11 @@ const RecipeIndexPage: FC<{ nodes: XContent[] }> = observer(({ nodes }) => {
3024

3125
return (
3226
<Container className="py-4">
33-
<PageHead title={`${t('recipes')} - ${t('knowledge_base')}`} />
27+
<PageHead title={`${t('recipe')} - ${t('knowledge_base')}`} />
3428

3529
<hgroup className="d-flex justify-content-between align-items-center mb-4">
3630
<h1>
37-
{t('recipes')} ({nodes.length})
31+
{t('recipe')} ({nodes.length})
3832
</h1>
3933
<Button
4034
href="https://github.com/Gar-b-age/CookLikeHOC"
@@ -46,23 +40,22 @@ const RecipeIndexPage: FC<{ nodes: XContent[] }> = observer(({ nodes }) => {
4640
</Button>
4741
</hgroup>
4842

49-
<div className="alert alert-info mb-4" role="alert">
50-
<p className="mb-1">
51-
<strong>感谢老乡鸡餐饮公司及开源菜谱仓库原作者</strong>
52-
</p>
53-
<p className="mb-0">
54-
本菜谱内容来自{' '}
55-
<a href="https://github.com/Gar-b-age/CookLikeHOC" target="_blank" rel="noopener noreferrer">
56-
CookLikeHOC 开源菜谱项目
57-
</a>
58-
,感谢原作者们的贡献与分享。
59-
</p>
60-
</div>
43+
<Alert variant="info" className="mb-4">
44+
本菜谱原创自
45+
<Alert.Link href="https://www.lxjchina.com.cn/display_4226.html" target="_blank">
46+
《老乡鸡菜品溯源报告》
47+
</Alert.Link>
48+
,并由{' '}
49+
<Alert.Link href="https://github.com/Gar-b-age/CookLikeHOC" target="_blank">
50+
CookLikeHOC 开源菜谱项目
51+
</Alert.Link>
52+
整理,感谢原作者们的贡献与分享。
53+
</Alert>
6154

6255
{nodes[0] ? (
63-
<ContentTree
64-
nodes={treeFrom(nodes, 'path', 'parent_path', 'children')}
65-
basePath="/recipes"
56+
<ContentTree
57+
nodes={treeFrom(nodes, 'path', 'parent_path', 'children')}
58+
basePath="/recipe"
6659
metaKey="category"
6760
/>
6861
) : (
@@ -77,4 +70,4 @@ const RecipeIndexPage: FC<{ nodes: XContent[] }> = observer(({ nodes }) => {
7770
);
7871
});
7972

80-
export default RecipeIndexPage;
73+
export default RecipeIndexPage;

translation/en-US.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,10 @@ export default {
102102
github_document_description: 'This is a document page based on a GitHub repository.',
103103
view_or_edit_on_github: 'View or edit this content on GitHub',
104104

105-
// Recipes
106-
recipes: 'Recipes',
105+
// Recipe
106+
recipe: 'Recipe',
107107
servings: 'Servings',
108-
prep_time: 'Prep Time',
108+
preparation_time: 'Preparation time',
109109

110110
// China NGO Map
111111
NGO: 'NGO',

translation/zh-CN.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ export default {
100100
github_document_description: '这是一个基于 GitHub 仓库的文档页面。',
101101
view_or_edit_on_github: '在 GitHub 上查看或编辑此内容',
102102

103-
// Recipes
104-
recipes: '菜谱',
103+
// Recipe
104+
recipe: '菜谱',
105105
servings: '份数',
106-
prep_time: '准备时间',
106+
preparation_time: '准备时间',
107107

108108
// China Public Interest Map
109109
NGO: '公益',

0 commit comments

Comments
 (0)