1+ import 'github-markdown-css/github-markdown-light.css' ;
2+
13import { marked } from 'marked' ;
24import { observer } from 'mobx-react' ;
35import { GetStaticPaths , GetStaticProps } from 'next' ;
@@ -6,82 +8,51 @@ import { FC, useContext } from 'react';
68import { Badge , Breadcrumb , Button , Card , Container } from 'react-bootstrap' ;
79
810import { PageHead } from '../../components/Layout/PageHead' ;
9- import { githubClient } from '../../models/Base' ;
11+ import type { Issue } from '../../models/Base' ;
12+ import { RepositoryModel } from '../../models/Base' ;
1013import { I18nContext } from '../../models/Translation' ;
1114import styles from '../../styles/Weekly.module.less' ;
1215
13- // GitHub Issue type definition
14- interface GitHubIssue {
15- id : number ;
16- number : number ;
17- title : string ;
18- body : string | null ;
19- state : 'open' | 'closed' ;
20- labels : Array < { name : string ; color : string } | string > ;
21- user : {
22- login : string ;
23- avatar_url : string ;
24- } | null ;
25- created_at : string ;
26- updated_at : string ;
27- html_url : string ;
28- }
29-
3016interface WeeklyDetailParams extends ParsedUrlQuery {
3117 id : string ;
3218}
3319
3420interface WeeklyDetailProps {
35- issue : GitHubIssue ;
21+ issue : Issue ;
3622}
3723
3824export const getStaticPaths : GetStaticPaths < WeeklyDetailParams > = async ( ) => {
39- try {
40- const { body : issues } = await githubClient . get < GitHubIssue [ ] > (
41- 'repos/FreeCodeCamp-Chengdu/IT-Technology-weekly/issues?state=all&sort=created&direction=desc' ,
42- ) ;
43-
44- const paths = ( issues || [ ] ) . map ( issue => ( {
45- params : { id : issue . number . toString ( ) } ,
46- } ) ) ;
47-
48- return { paths, fallback : 'blocking' } ;
49- } catch ( error ) {
50- console . error ( 'Failed to generate static paths:' , error ) ;
51-
52- return { paths : [ ] , fallback : 'blocking' } ;
53- }
25+ const repository = new RepositoryModel ( 'FreeCodeCamp-Chengdu' ) ;
26+ const repo = await repository . getOne ( 'IT-Technology-weekly' , [ 'issues' ] ) ;
27+
28+ const paths = ( repo . issues || [ ] ) . map ( issue => ( {
29+ params : { id : issue . number . toString ( ) } ,
30+ } ) ) ;
31+
32+ return { paths, fallback : 'blocking' } ;
5433} ;
5534
5635export const getStaticProps : GetStaticProps < WeeklyDetailProps , WeeklyDetailParams > = async ( {
5736 params,
5837} ) => {
5938 const { id } = params ! ;
60-
61- try {
62- const { body : issue } = await githubClient . get < GitHubIssue > (
63- `repos/FreeCodeCamp-Chengdu/IT-Technology-weekly/issues/${ id } ` ,
64- ) ;
65-
66- if ( ! issue ) {
67- return {
68- notFound : true ,
69- } ;
70- }
71-
72- return {
73- props : {
74- issue : JSON . parse ( JSON . stringify ( issue ) ) ,
75- } ,
76- revalidate : 3600 , // Revalidate every hour
77- } ;
78- } catch ( error ) {
79- console . error ( 'Failed to fetch issue:' , error ) ;
80-
39+ const repository = new RepositoryModel ( 'FreeCodeCamp-Chengdu' ) ;
40+ const repo = await repository . getOne ( 'IT-Technology-weekly' , [ 'issues' ] ) ;
41+
42+ const issue = repo . issues ?. find ( issue => issue . number . toString ( ) === id ) ;
43+
44+ if ( ! issue ) {
8145 return {
8246 notFound : true ,
8347 } ;
8448 }
49+
50+ return {
51+ props : {
52+ issue : JSON . parse ( JSON . stringify ( issue ) ) ,
53+ } ,
54+ revalidate : 3600 , // Revalidate every hour
55+ } ;
8556} ;
8657
8758const WeeklyDetailPage : FC < WeeklyDetailProps > = observer ( ( { issue } ) => {
@@ -96,7 +67,7 @@ const WeeklyDetailPage: FC<WeeklyDetailProps> = observer(({ issue }) => {
9667 />
9768
9869 < Breadcrumb className = "mb-4" >
99- < Breadcrumb . Item href = "/" > 首页 </ Breadcrumb . Item >
70+ < Breadcrumb . Item href = "/" > { t ( 'home_page' ) } </ Breadcrumb . Item >
10071 < Breadcrumb . Item href = "/weekly" > { t ( 'weekly' ) } </ Breadcrumb . Item >
10172 < Breadcrumb . Item active > #{ issue . number } </ Breadcrumb . Item >
10273 </ Breadcrumb >
@@ -112,62 +83,70 @@ const WeeklyDetailPage: FC<WeeklyDetailProps> = observer(({ issue }) => {
11283
11384 < h1 className = "display-5 mb-3" > { issue . title } </ h1 >
11485
115- { issue . labels && issue . labels . length > 0 && (
116- < div className = "mb-3" >
86+ { issue . labels ?. [ 0 ] && (
87+ < ul className = "list-unstyled mb-3" >
11788 { issue . labels . map ( ( label , index ) => (
118- < Badge
119- key = { index }
120- bg = "light"
121- text = "dark"
122- className = { `me-2 mb-2 ${ styles . labelBadge } ` }
123- >
124- { typeof label === 'string' ? label : label . name }
125- </ Badge >
89+ < li key = { index } className = "d-inline-block me-2 mb-2" >
90+ < Badge
91+ bg = "light"
92+ text = "dark"
93+ className = { styles . labelBadge }
94+ >
95+ { typeof label === 'string' ? label : label . name }
96+ </ Badge >
97+ </ li >
12698 ) ) }
127- </ div >
99+ </ ul >
128100 ) }
129101
130- < div className = "d-flex justify-content-between align-items-center mb-4 pb-3 border-bottom" >
131- < div className = "text-muted" >
132- { issue . user && (
133- < span >
134- { t ( 'weekly_author' ) } : < strong > { issue . user . login } </ strong >
135- </ span >
136- ) }
137- { issue . created_at && (
138- < span className = "ms-3" >
139- { t ( 'weekly_published' ) } :{ ' ' }
102+ < dl className = "row mb-4 pb-3 border-bottom" >
103+ { issue . user && (
104+ < >
105+ < dt className = "col-sm-3 text-muted" > { t ( 'weekly_author' ) } :</ dt >
106+ < dd className = "col-sm-9" >
107+ < strong > { issue . user . login } </ strong >
108+ </ dd >
109+ </ >
110+ ) }
111+ { issue . created_at && (
112+ < >
113+ < dt className = "col-sm-3 text-muted" > { t ( 'weekly_published' ) } :</ dt >
114+ < dd className = "col-sm-9" >
140115 < time dateTime = { issue . created_at } >
141116 { new Date ( issue . created_at ) . toLocaleString ( 'zh-CN' ) }
142117 </ time >
143- </ span >
144- ) }
145- { issue . updated_at && issue . updated_at !== issue . created_at && (
146- < span className = "ms-3" >
147- { t ( 'weekly_updated' ) } :{ ' ' }
118+ </ dd >
119+ </ >
120+ ) }
121+ { issue . updated_at && issue . updated_at !== issue . created_at && (
122+ < >
123+ < dt className = "col-sm-3 text-muted" > { t ( 'weekly_updated' ) } :</ dt >
124+ < dd className = "col-sm-9" >
148125 < time dateTime = { issue . updated_at } >
149126 { new Date ( issue . updated_at ) . toLocaleString ( 'zh-CN' ) }
150127 </ time >
151- </ span >
152- ) }
153- </ div >
154-
155- < div className = "d-flex gap-2" >
156- < Button
157- variant = "outline-primary"
158- size = "sm"
159- href = { issue . html_url }
160- target = "_blank"
161- rel = "noopener noreferrer"
162- >
163- { t ( 'view_on_github' ) }
164- </ Button >
165- </ div >
128+ </ dd >
129+ </ >
130+ ) }
131+ </ dl >
132+ < div className = "d-flex justify-content-end mb-4" >
133+ < Button
134+ variant = "outline-primary"
135+ size = "sm"
136+ href = { issue . html_url }
137+ target = "_blank"
138+ rel = "noopener noreferrer"
139+ >
140+ { t ( 'view_on_github' ) }
141+ </ Button >
166142 </ div >
167143 </ header >
168144
169145 { htmlContent ? (
170- < div dangerouslySetInnerHTML = { { __html : htmlContent } } className = { styles . markdownBody } />
146+ < div
147+ dangerouslySetInnerHTML = { { __html : htmlContent } }
148+ className = "markdown-body"
149+ />
171150 ) : (
172151 < Card >
173152 < Card . Body className = "text-center text-muted" >
@@ -184,7 +163,7 @@ const WeeklyDetailPage: FC<WeeklyDetailProps> = observer(({ issue }) => {
184163 </ Button >
185164
186165 < div className = "text-muted small" >
187- < p className = "mb-0" >
166+ < p >
188167 { t ( 'github_document_description' ) }
189168 < a href = { issue . html_url } target = "_blank" rel = "noopener noreferrer" className = "ms-1" >
190169 { t ( 'view_original_on_github' ) }
0 commit comments