From 89e10633cff891d3f6c737b93bc1271b60d62a00 Mon Sep 17 00:00:00 2001 From: dethan3 Date: Mon, 17 Mar 2025 14:57:56 +0000 Subject: [PATCH 1/8] feat(home): add "view all" buttons for events, blogs, and partners --- .env | 2 +- components/Home/CommunityStats.tsx | 27 +++++++++ components/Home/LatestBlogs.tsx | 40 +++++++++++++ components/Home/Sponsors.tsx | 34 +++++++++++ components/Home/UpcomingEvents.tsx | 42 +++++++++++++ components/Layout/Footer.tsx | 0 components/Navigator/MainNavigator.tsx | 13 +--- pages/about.tsx | 33 ++++++++++ pages/activity.tsx | 0 pages/community.tsx | 0 pages/index.tsx | 83 ++++++++++---------------- styles/About.module.less | 15 +++++ styles/Home.module.less | 12 ++++ styles/globals.less | 10 ++++ translation/en-US.ts | 7 +++ translation/zh-CN.ts | 9 ++- translation/zh-TW.ts | 7 +++ 17 files changed, 269 insertions(+), 65 deletions(-) create mode 100644 components/Home/CommunityStats.tsx create mode 100644 components/Home/LatestBlogs.tsx create mode 100644 components/Home/Sponsors.tsx create mode 100644 components/Home/UpcomingEvents.tsx create mode 100644 components/Layout/Footer.tsx create mode 100644 pages/about.tsx create mode 100644 pages/activity.tsx create mode 100644 pages/community.tsx create mode 100644 styles/About.module.less diff --git a/.env b/.env index b69254bc2..14a3ba6c3 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -NEXT_PUBLIC_SITE_NAME=freecodecamp-chengdu.github.io +NEXT_PUBLIC_SITE_NAME=fCC-ChengDu NEXT_PUBLIC_SITE_SUMMARY=Lark project scaffold based on TypeScript, React, Next.js, Bootstrap & Workbox. NEXT_PUBLIC_SENTRY_DSN = diff --git a/components/Home/CommunityStats.tsx b/components/Home/CommunityStats.tsx new file mode 100644 index 000000000..2985e7ac2 --- /dev/null +++ b/components/Home/CommunityStats.tsx @@ -0,0 +1,27 @@ +import { Card,Col, Container, Row } from 'react-bootstrap'; + +export const CommunityStats = () => ( + +

+ 社区数据 + {/*
*/} +

+ + {[ + { number: '1000+', label: '社区成员' }, + { number: '50+', label: '举办活动' }, + { number: '200+', label: '技术文章' }, + { number: '30+', label: '开源项目' }, + ].map((stat, index) => ( + + + +

{stat.number}

+

{stat.label}

+
+
+ + ))} +
+
+); diff --git a/components/Home/LatestBlogs.tsx b/components/Home/LatestBlogs.tsx new file mode 100644 index 000000000..f3b16e653 --- /dev/null +++ b/components/Home/LatestBlogs.tsx @@ -0,0 +1,40 @@ +import Link from 'next/link'; +import { Button,Card, Col, Container, Row } from 'react-bootstrap'; + +export const LatestBlogs = () => ( + +

最新博客文章

+ + + + + 如何学习 TypeScript? + 发布日期: 2025年3月10日 + + 阅读文章 + + + + + + + + React 18 新特性 + 发布日期: 2025年2月25日 + + 阅读文章 + + + + + + +
+ + + +
+
+); diff --git a/components/Home/Sponsors.tsx b/components/Home/Sponsors.tsx new file mode 100644 index 000000000..7b5b7aaaf --- /dev/null +++ b/components/Home/Sponsors.tsx @@ -0,0 +1,34 @@ +import Link from 'next/link'; +import { Button,Card, Col, Container, Row } from 'react-bootstrap'; + +export const Sponsors = () => ( + +

赞助商与合作伙伴

+ + + + + 企业 A + 领先的技术公司,支持开源社区。 + + + + + + + 企业 B + 专注于智能具身领域的创新公司。 + + + + + +
+ + + +
+
+); diff --git a/components/Home/UpcomingEvents.tsx b/components/Home/UpcomingEvents.tsx new file mode 100644 index 000000000..aa53a9cab --- /dev/null +++ b/components/Home/UpcomingEvents.tsx @@ -0,0 +1,42 @@ +import Link from 'next/link'; +import { Button,Card, Col, Container, Row } from 'react-bootstrap'; + +export const UpcomingEvents = () => ( + +

即将举行的活动

+ + + + + 活动标题 1 + 时间: 2025年3月20日 + 地点: 成都某咖啡馆 + + 查看详情 + + + + + + + + 活动标题 2 + 时间: 2025年4月5日 + 地点: 线上直播 + + 查看详情 + + + + + + +
+ + + +
+
+); diff --git a/components/Layout/Footer.tsx b/components/Layout/Footer.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/components/Navigator/MainNavigator.tsx b/components/Navigator/MainNavigator.tsx index c72b1b32b..b83c1ae17 100644 --- a/components/Navigator/MainNavigator.tsx +++ b/components/Navigator/MainNavigator.tsx @@ -20,18 +20,11 @@ export const MainNavigator: FC = observer(() => ( diff --git a/pages/about.tsx b/pages/about.tsx new file mode 100644 index 000000000..173492f8c --- /dev/null +++ b/pages/about.tsx @@ -0,0 +1,33 @@ +import { observer } from 'mobx-react'; +import { compose, translator } from 'next-ssr-middleware'; +import { Container } from 'react-bootstrap'; + +import { PageHead } from '../components/Layout/PageHead'; +import { i18n, t } from '../models/Translation'; +import styles from '../styles/About.module.less'; + +export const getServerSideProps = compose(translator(i18n)); + +const AboutPage = observer(() => ( + + + +

{t('about_us')}

+

+ FCC 成都社区, 成立于 2016 年 6 + 月,是一个非营利性的公益性技术社区,是由一群热血有志青年爱好者,利用个人业余休息时间组建而成的技术社区,目的是为了搭建一个友好的交流、学习、互助的社区,帮助成都市众多的开发者,技术爱好者提升个人技术能力。社区致力于做西南地区首个有温度与情怀的技术社区,鼓励人人皆可编程实现个人梦想。 +

+ +
+

{t('our_mission')}

+

让更多人享受编程的乐趣,并改变自己的生活。

+
+ +
+

{t('our_team')}

+

。。。

+
+
+)); + +export default AboutPage; diff --git a/pages/activity.tsx b/pages/activity.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/pages/community.tsx b/pages/community.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/pages/index.tsx b/pages/index.tsx index a6e0e1b25..4eec01e8b 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,71 +1,48 @@ import { observer } from 'mobx-react'; import { compose, translator } from 'next-ssr-middleware'; -import { Card, Col, Container, Row } from 'react-bootstrap'; +import { Button,Card, Col, Container, Row } from 'react-bootstrap'; -import { GitCard } from '../components/Git/Card'; +import { CommunityStats } from '../components/Home/CommunityStats'; +import { LatestBlogs } from '../components/Home/LatestBlogs'; +import { Sponsors } from '../components/Home/Sponsors'; +import { UpcomingEvents } from '../components/Home/UpcomingEvents'; import { PageHead } from '../components/Layout/PageHead'; import { i18n, t } from '../models/Translation'; import styles from '../styles/Home.module.less'; -import { framework, mainNav } from './api/home'; export const getServerSideProps = compose(translator(i18n)); const HomePage = observer(() => ( - + + + + +

freeCodeCamp 成都社区

+
+

+ 一个友好的技术社区,致力于交流、学习和互助,帮助成都的开发者和技术爱好者提升个人技术能力。 +

+
+ + +
+ + + {/* */} +
-

- {t('welcome_to')} - - Next.js! - -

+ -

- {t('get_started_by_editing')} - - pages/index.tsx - -

+ - - {mainNav().map(({ link, title, summary }) => ( - - - - - - {title} → - - - {summary} - - - - ))} - + -

{t('upstream_projects')}

- - {framework.map( - ({ title, languages, tags, summary, link, repository }) => ( - - - - ), - )} - +
)); diff --git a/styles/About.module.less b/styles/About.module.less new file mode 100644 index 000000000..3a811e0c6 --- /dev/null +++ b/styles/About.module.less @@ -0,0 +1,15 @@ +.main { + margin: auto; + padding: 2rem; + max-width: 800px; +} + +.main h1, +.main h2 { + color: #0070f3; + text-align: center; +} + +.main p { + line-height: 1.6; +} diff --git a/styles/Home.module.less b/styles/Home.module.less index 6e9bf39b6..43e89d03f 100644 --- a/styles/Home.module.less +++ b/styles/Home.module.less @@ -3,6 +3,18 @@ min-height: 100vh; } +.imagePlaceholder { + display: flex; + justify-content: center; + align-items: center; + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); + border-radius: 16px; + background: #f0f0f0; + width: 80%; + max-width: 400px; + height: 300px; +} + .title { font-size: 4rem; line-height: 1.15; diff --git a/styles/globals.less b/styles/globals.less index 7b2851f5b..123889418 100644 --- a/styles/globals.less +++ b/styles/globals.less @@ -1,6 +1,11 @@ html, body { margin: 0; + background-image: linear-gradient( + 150deg, + #028dfa 60%, + #0ee6e6 100% + ) !important; padding: 0; font-family: -apple-system, @@ -42,3 +47,8 @@ div:has(.next-error-h1) { width: auto !important; } } + +:root { + --bs-primary: #000000; + --bs-primary-rgb: 2, 141, 250; +} diff --git a/translation/en-US.ts b/translation/en-US.ts index 2d682c8c5..36bac0a5b 100644 --- a/translation/en-US.ts +++ b/translation/en-US.ts @@ -1,6 +1,13 @@ import { IDType } from 'mobx-restful'; export default { + about: 'About', + about_us: 'About US', + our_team: 'Our Team', + our_mission: 'Our Mission', + activity: 'Activity', + community_description: 'Let more people enjoy the fun of programming', + community: 'Community', welcome_to: 'Welcome to', get_started_by_editing: 'Get started by editing', upstream_projects: 'Upstream projects', diff --git a/translation/zh-CN.ts b/translation/zh-CN.ts index 65a569823..19958ce58 100644 --- a/translation/zh-CN.ts +++ b/translation/zh-CN.ts @@ -1,7 +1,14 @@ import { IDType } from 'mobx-restful'; export default { - welcome_to: '欢迎使用', + about: '关于', + about_us: '关于我们', + our_mission: '我们的使命', + our_team: '我们的团队', + activity: '活动', + community_description: '让更多人享受编程的乐趣', + community: '社区', + welcome_to: '欢迎来到', get_started_by_editing: '开始你的项目吧,编辑', upstream_projects: '上游项目', home_page: '主页', diff --git a/translation/zh-TW.ts b/translation/zh-TW.ts index 1eca7cdd9..00c620ca1 100644 --- a/translation/zh-TW.ts +++ b/translation/zh-TW.ts @@ -1,6 +1,13 @@ import { IDType } from 'mobx-restful'; export default { + about: '關於', + about_us: '關於我們', + our_mission: '我們的使命', + our_team: '我們的團隊', + activity: '活動', + community_description: '讓更多人享受程式設計的樂趣', + community: '社群', welcome_to: '歡迎使用', get_started_by_editing: '開始你的專案吧,編輯', upstream_projects: '上游專案', From de0fe92ed41feaa5ee789432dd7612f5527e0345 Mon Sep 17 00:00:00 2001 From: dethan3 Date: Fri, 9 May 2025 00:53:02 +0800 Subject: [PATCH 2/8] refactor: convert About page to use Bootstrap utility classes and add comprehensive community content --- .env | 4 +- components/Home/CommunityStats.tsx | 9 +- components/Home/LatestBlogs.tsx | 54 +++++---- components/Home/Sponsors.tsx | 44 ++++---- components/Home/UpcomingEvents.tsx | 58 +++++----- components/Layout/Footer.tsx | 0 components/Navigator/MainNavigator.tsx | 4 + package.json | 7 ++ pages/about.tsx | 146 +++++++++++++++++++++++-- pages/activity.tsx | 0 pages/api/core.ts | 67 ++++++------ pages/index.tsx | 97 ++++++++++++++-- styles/About.module.less | 15 --- 13 files changed, 348 insertions(+), 157 deletions(-) delete mode 100644 components/Layout/Footer.tsx delete mode 100644 pages/activity.tsx delete mode 100644 styles/About.module.less diff --git a/.env b/.env index 68969b27b..8763eff34 100644 --- a/.env +++ b/.env @@ -1,5 +1,5 @@ -NEXT_PUBLIC_SITE_NAME=fCC-ChengDu -NEXT_PUBLIC_SITE_SUMMARY=Lark project scaffold based on TypeScript, React, Next.js, Bootstrap & Workbox. +NEXT_PUBLIC_SITE_NAME=fCC 成都社区 +NEXT_PUBLIC_SITE_SUMMARY=fCC 成都社区 NEXT_PUBLIC_LOGO = https://github.com/FreeCodeCamp-Chengdu.png NEXT_PUBLIC_SENTRY_DSN = diff --git a/components/Home/CommunityStats.tsx b/components/Home/CommunityStats.tsx index 2985e7ac2..8bef15924 100644 --- a/components/Home/CommunityStats.tsx +++ b/components/Home/CommunityStats.tsx @@ -4,7 +4,6 @@ export const CommunityStats = () => (

社区数据 - {/*
*/}

{[ @@ -12,12 +11,12 @@ export const CommunityStats = () => ( { number: '50+', label: '举办活动' }, { number: '200+', label: '技术文章' }, { number: '30+', label: '开源项目' }, - ].map((stat, index) => ( - + ].map(({ number, label }) => ( + -

{stat.number}

-

{stat.label}

+

{number}

+

{label}

diff --git a/components/Home/LatestBlogs.tsx b/components/Home/LatestBlogs.tsx index f3b16e653..30e092bcb 100644 --- a/components/Home/LatestBlogs.tsx +++ b/components/Home/LatestBlogs.tsx @@ -1,40 +1,36 @@ import Link from 'next/link'; -import { Button,Card, Col, Container, Row } from 'react-bootstrap'; +import { Button, Card, Col, Container, Row } from 'react-bootstrap'; +import { ArticleMeta } from '../../pages/api/core'; -export const LatestBlogs = () => ( +interface LatestBlogsProps { + articles: ArticleMeta[]; +} + +export const LatestBlogs: React.FC = ({ articles }) => (

最新博客文章

- - - - 如何学习 TypeScript? - 发布日期: 2025年3月10日 - - 阅读文章 - - - - - - - - React 18 新特性 - 发布日期: 2025年2月25日 - - 阅读文章 - - - - + {articles.map((article) => ( + + + + {article.name} + + 发布日期: {article.meta?.date || '未知日期'} + + + 阅读文章 + + + + + ))}
- - - +
); diff --git a/components/Home/Sponsors.tsx b/components/Home/Sponsors.tsx index 7b5b7aaaf..5754f9401 100644 --- a/components/Home/Sponsors.tsx +++ b/components/Home/Sponsors.tsx @@ -1,34 +1,30 @@ -import Link from 'next/link'; -import { Button,Card, Col, Container, Row } from 'react-bootstrap'; +import { Button, Card, Col, Container, Row } from 'react-bootstrap'; +import { ArticleMeta } from '../../pages/api/core'; -export const Sponsors = () => ( +interface SponsorsProps { + sponsors: ArticleMeta[]; +} + +export const Sponsors: React.FC = ({ sponsors }) => (

赞助商与合作伙伴

- - - - 企业 A - 领先的技术公司,支持开源社区。 - - - - - - - 企业 B - 专注于智能具身领域的创新公司。 - - - + {sponsors.map((sponsor) => ( + + + + {sponsor.name} + {sponsor.meta?.description || '暂无描述'} + + + + ))}
- - - +
); diff --git a/components/Home/UpcomingEvents.tsx b/components/Home/UpcomingEvents.tsx index aa53a9cab..e8b48f76a 100644 --- a/components/Home/UpcomingEvents.tsx +++ b/components/Home/UpcomingEvents.tsx @@ -1,42 +1,36 @@ import Link from 'next/link'; -import { Button,Card, Col, Container, Row } from 'react-bootstrap'; +import { Button, Card, Col, Container, Row } from 'react-bootstrap'; +import { ArticleMeta } from '../../pages/api/core'; -export const UpcomingEvents = () => ( +interface UpcomingEventsProps { + events: ArticleMeta[]; +} + +export const UpcomingEvents: React.FC = ({ events }) => ( -

即将举行的活动

+

往期活动

- - - - 活动标题 1 - 时间: 2025年3月20日 - 地点: 成都某咖啡馆 - - 查看详情 - - - - - - - - 活动标题 2 - 时间: 2025年4月5日 - 地点: 线上直播 - - 查看详情 - - - - + {events.map((event) => ( + + + + {event.meta?.title} + 时间: {event.meta?.start || 'void 0'} + 地点: {event.meta?.address || 'void 0'} + {/* TODO: 无 Path 不渲染 */} + + 查看详情 + + + + + ))}
- - - +
); diff --git a/components/Layout/Footer.tsx b/components/Layout/Footer.tsx deleted file mode 100644 index e69de29bb..000000000 diff --git a/components/Navigator/MainNavigator.tsx b/components/Navigator/MainNavigator.tsx index b83c1ae17..02ca0bb51 100644 --- a/components/Navigator/MainNavigator.tsx +++ b/components/Navigator/MainNavigator.tsx @@ -25,6 +25,10 @@ export const MainNavigator: FC = observer(() => ( {t('community')} {t('about')} + + + {t('source_code')} + diff --git a/package.json b/package.json index 3168eadf7..bf2f2edb8 100644 --- a/package.json +++ b/package.json @@ -97,5 +97,12 @@ "test": "lint-staged && npm run lint", "pack-image": "docker build -t freecodecamp-chengdu/freecodecamp-chengdu.github.io:latest .", "container": "docker rm -f freecodecamp-chengdu.github.io && docker run --name freecodecamp-chengdu.github.io -p 3000:3000 -d freecodecamp-chengdu/freecodecamp-chengdu.github.io:latest" + }, + "pnpm": { + "ignoredBuiltDependencies": [ + "@sentry/cli", + "core-js", + "sharp" + ] } } diff --git a/pages/about.tsx b/pages/about.tsx index 173492f8c..b11d5e751 100644 --- a/pages/about.tsx +++ b/pages/about.tsx @@ -1,31 +1,157 @@ import { observer } from 'mobx-react'; import { compose, translator } from 'next-ssr-middleware'; -import { Container } from 'react-bootstrap'; - +import { Container, Table } from 'react-bootstrap'; import { PageHead } from '../components/Layout/PageHead'; import { i18n, t } from '../models/Translation'; -import styles from '../styles/About.module.less'; export const getServerSideProps = compose(translator(i18n)); const AboutPage = observer(() => ( - +

{t('about_us')}

- FCC 成都社区, 成立于 2016 年 6 - 月,是一个非营利性的公益性技术社区,是由一群热血有志青年爱好者,利用个人业余休息时间组建而成的技术社区,目的是为了搭建一个友好的交流、学习、互助的社区,帮助成都市众多的开发者,技术爱好者提升个人技术能力。社区致力于做西南地区首个有温度与情怀的技术社区,鼓励人人皆可编程实现个人梦想。 + FCC 成都社区, 成立于 2016 年 6 月,是一个非营利性的公益性技术社区,是由一群热血有志青年爱好者,利用个人业余休息时间组建而成的技术社区,目的是为了搭建一个友好的交流、学习、互助的社区,帮助成都市众多的开发者,技术爱好者提升个人技术能力。社区致力于做西南地区首个有温度与情怀的技术社区,鼓励人人皆可编程实现个人梦想。

-

{t('our_mission')}

-

让更多人享受编程的乐趣,并改变自己的生活。

+

什么是 FCC

+

+ freeCodeCamp(简称 FCC)是由美国人 Quincy Larson 发起的开源项目,截止 2018-02-03,在 Github 上获得 29+万 Star(教育类排名第一)。有长达 1600 小时的课程, 并且是基于浏览器、课程免费、证书免费、结合了游戏化闯关的乐趣。FCC 是一个在 160 多个国家和 2000 多个城市的拥有与 1000k+ 开发者的社区。 +

+

+ 2016 年 4 月,由 DevEco (晋剑 + Miya)将 FCC 引入中国,并举办了 2000+ 开发者参与的在线全民编程活动,到目前为止,已成功举办了 100+ 场 Coffee & Code / 编程黑客松 / 编程静修日等活动。在 FCC China , 有 20+% 的女性加入到了社区学习、提升编程能力。 +

+
+ +
+

{t('our_mission')}

+

让更多人享受编程的乐趣,并改变自己的生活。

+
+ +
+

FCC 成都社区活动

+

大型活动

+
    +
  • FCC 成都社区 React 技术专场交流活动
  • +
  • 2017 成都首届 Web 前端交流大会
  • +
  • 新耀杯 Code for City 黑客松大赛
  • +
+ +

历史活动

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
序号日期主题形式
120160609线下活动开启,宣布社区成立编程讨论
220160703携手编程-成都社区主页初版动手编程
320160911结对编程的理念个人分享 + 结对编程
420161106Console 的九大命令 + 学习路线分享个人分享
520161119Git 的使用与个人简历制作分享 + 编程
+
+

显示部分历史活动,完整列表请参考原文档

+
+ +
+

为什么是 FCC 成都社区

+

+ 在成都众多的技术大会、技术分享活动当中,很多的活动以技术分享为幌子,做着产品推广与宣传的事情,这导致了成都 IT 圈子技术分享的氛围越来越差,大家参与分享的热情越来越低。 +

+

+ FCC 成都社区的众多小伙伴,一致认为是时候为这座热爱的城市做一份自己的贡献了,社区提出所有活动全部免费参加、嘉宾分享内容中广告零容忍,成立嘉宾分享内容审查团队,确保每一次分享都是 100% 的干货。 +

+

+ FCC 成都社区的小伙伴们一直明白社区所肩负的使命,带动成都 IT 圈子技术交流的氛围,让更多的技术牛人帮助到更多的开发者,让成都成为全国 IT 行业的先锋,让成都吸引更多 IT 人才蓉漂。进入更多的校园普及更多的次的编程知识,倡导人人皆可编程,让成都这座城市未来充满无限可能。 +

+
+ +
+

FCC 成都社区规划

+
    +
  1. 走进更多校园,普及人人皆可编程思想帮助更多的孩子们。
  2. +
  3. 继续坚持做好两周一次的【Coffee and Code】的结对编程活动、编程道场活动,一对一指导开发者提升个人技术能力。
  4. +
  5. 做好季度技术专场活动,让成都众多 IT 公司加入其中进行分享,带动成都 IT 圈子技术分享的热情。
  6. +
  7. 做好成都 Web 前端交流大会,让国内一线技术大咖来到成都,给成都众多开发者带来国内一线开发公司的技术心得与经验。
  8. +
  9. 联合成都众多大型 IT 公司,做好编程马拉松活动,让成都的众多开发者进行技术火花的碰撞。
  10. +
+
+ +
+

{t('our_team')}

+

。。。

-

{t('our_team')}

-

。。。

+

媒体报道

+
+
+
+
+

四川电视台报道

+

四川电视台黑客松报道

+
+
+
+
+
+
+

成都市高新电视台报道

+

2017 成都 Web 前端交流大会 (6 分 53 秒处)

+
+
+
+
+
+
+

四川财富广播 FM94.0 采访

+

FCC 成都社区:“人人皆可编程”,以独特的方式为城市带来美好改变

+
+
+
+
+
+
+

四川日报报道

+

揭秘“黑客马拉松”:喝 6 瓶红牛、24 小时里只睡 2 小时

+
+
+
+
)); diff --git a/pages/activity.tsx b/pages/activity.tsx deleted file mode 100644 index e69de29bb..000000000 diff --git a/pages/api/core.ts b/pages/api/core.ts index abd75ddf5..16ae8a067 100644 --- a/pages/api/core.ts +++ b/pages/api/core.ts @@ -56,13 +56,15 @@ export interface ArticleMeta { const MDX_pattern = /\.mdx?$/; export async function frontMatterOf(path: string) { - const { readFile } = await import('fs/promises'); - - const file = await readFile(path, 'utf-8'); - - const [, frontMatter] = file.match(/^---[\r\n]([\s\S]+?[\r\n])---/) || []; - - return frontMatter && parse(frontMatter); + try { + const { readFile } = await import('fs/promises'); + const file = await readFile(path, 'utf-8'); + const [, frontMatter] = file.match(/^---[\r\n]([\s\S]+?[\r\n])---/) || []; + return frontMatter ? parse(frontMatter) : null; + } catch (error) { + console.error(`Error reading front matter from ${path}:`, error); + return null; + } } export async function* pageListOf( @@ -71,36 +73,39 @@ export async function* pageListOf( ): AsyncGenerator { const { readdir } = await import('fs/promises'); - const list = await readdir(prefix + path, { withFileTypes: true }); - - for (const node of list) { - let { name, path } = node; + try { + const list = await readdir(prefix + path, { withFileTypes: true }); - if (name.startsWith('.')) continue; + for (const node of list) { + let { name, path } = node; - const isMDX = MDX_pattern.test(name); + if (name.startsWith('.')) continue; - name = name.replace(MDX_pattern, ''); - path = `${path}/${name}`.replace(new RegExp(`^${prefix}`), ''); + const isMDX = MDX_pattern.test(name); - if (node.isFile()) - if (isMDX) { - const article: ArticleMeta = { name, path, subs: [] }; - try { - const meta = await frontMatterOf(`${node.path}/${node.name}`); + name = name.replace(MDX_pattern, ''); + path = `${path}/${name}`.replace(new RegExp(`^${prefix}`), ''); - if (meta) article.meta = meta; - } catch (error) { - console.error(error); + if (node.isFile()) { + if (isMDX) { + const article: ArticleMeta = { name, path, subs: [] }; + try { + const meta = await frontMatterOf(`${node.path}/${node.name}`); + if (meta) article.meta = meta; + yield article; + } catch (error) { + console.error(`Error reading front matter for ${node.path}/${node.name}:`, error); + } } - yield article; - } else continue; - - if (!node.isDirectory()) continue; - - const subs = await Array.fromAsync(pageListOf(path, prefix)); - - if (subs[0]) yield { name, subs }; + } else if (node.isDirectory()) { + const subs = await Array.fromAsync(pageListOf(path, prefix)); + if (subs.length > 0) { + yield { name, subs }; + } + } + } + } catch (error) { + console.error(`Error reading directory ${prefix + path}:`, error); } } diff --git a/pages/index.tsx b/pages/index.tsx index 4eec01e8b..9964eabbc 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,6 +1,6 @@ import { observer } from 'mobx-react'; import { compose, translator } from 'next-ssr-middleware'; -import { Button,Card, Col, Container, Row } from 'react-bootstrap'; +import { Button, Col, Container, Row } from 'react-bootstrap'; import { CommunityStats } from '../components/Home/CommunityStats'; import { LatestBlogs } from '../components/Home/LatestBlogs'; @@ -8,11 +8,92 @@ import { Sponsors } from '../components/Home/Sponsors'; import { UpcomingEvents } from '../components/Home/UpcomingEvents'; import { PageHead } from '../components/Layout/PageHead'; import { i18n, t } from '../models/Translation'; +import { ArticleMeta, pageListOf, traverseTree } from './api/core'; import styles from '../styles/Home.module.less'; -export const getServerSideProps = compose(translator(i18n)); +interface HomePageProps { + latestArticles: ArticleMeta[]; + upcomingEvents: ArticleMeta[]; + sponsors: ArticleMeta[]; +} -const HomePage = observer(() => ( +export const getStaticProps = async () => { + try { + console.log('Starting to fetch data...'); + const [articles, activities, partners] = await Promise.all([ + Array.fromAsync(pageListOf('/article/Wiki/_posts/Article/Translation')), + Array.fromAsync(pageListOf('/article/Wiki/_posts/Activity')), + Array.fromAsync(pageListOf('/article/Wiki/_posts/Partner')) + ]); + + console.log('Raw articles:', articles); + console.log('Raw activities:', activities); + console.log('Raw partners:', partners); + + const latestArticles = articles + // .map(root => { + // let message = [...traverseTree(root, 'subs')]; + // console.log('123:', root); + // return message; + // }) + .flat() + .filter((article): article is ArticleMeta => 'meta' in article) + .sort((a, b) => { + const dateA = a.meta?.date ? new Date(a.meta.date).getTime() : 0; + const dateB = b.meta?.date ? new Date(b.meta.date).getTime() : 0; + return dateB - dateA; // Sort in descending order (newest first) + }) + .slice(0, 3); + + console.log('Processed latestArticles:', latestArticles); + + const upcomingEvents = activities + .map(root => { + let message = [...traverseTree(root, 'subs')] + console.log('aabbcc:', message); + return message; + }) + .flat() + .filter((event): event is ArticleMeta => 'meta' in event) + // .filter(event => { + // const eventDate = event.meta?.date ? new Date(event.meta.date) : null; + // return eventDate && eventDate > new Date(); // Only keep future events + // }) + .sort((a, b) => { + const dateA = a.meta?.date ? new Date(a.meta.date).getTime() : 0; + const dateB = b.meta?.date ? new Date(b.meta.date).getTime() : 0; + return dateB - dateA; // Sort in ascending order (nearest future first) + }) + .slice(0, 3); + + console.log('Processed upcomingEvents:', upcomingEvents); + + const sponsors = partners + // .map(root => [...traverseTree(root, 'subs')]) + .flat() + .filter((sponsor): sponsor is ArticleMeta => 'meta' in sponsor) + .slice(0, 3); + + console.log('Processed sponsors:', sponsors); + + return { + props: { latestArticles, upcomingEvents, sponsors }, + revalidate: 3600 // Revalidate every hour + }; + } catch (error) { + console.error('Error fetching data:', error); + return { + props: { + latestArticles: [], + upcomingEvents: [], + sponsors: [] + }, + revalidate: 3600 + }; + } +}; + +const HomePage = observer(({ latestArticles, upcomingEvents, sponsors }: HomePageProps) => ( @@ -24,7 +105,7 @@ const HomePage = observer(() => ( 一个友好的技术社区,致力于交流、学习和互助,帮助成都的开发者和技术爱好者提升个人技术能力。

-
- - {/* */}
- + - + - +
)); diff --git a/styles/About.module.less b/styles/About.module.less deleted file mode 100644 index 3a811e0c6..000000000 --- a/styles/About.module.less +++ /dev/null @@ -1,15 +0,0 @@ -.main { - margin: auto; - padding: 2rem; - max-width: 800px; -} - -.main h1, -.main h2 { - color: #0070f3; - text-align: center; -} - -.main p { - line-height: 1.6; -} From 9a14c8765cefe61a415fdf80af04646766f85e14 Mon Sep 17 00:00:00 2001 From: dethan3 Date: Fri, 9 May 2025 00:53:38 +0800 Subject: [PATCH 3/8] refactor: convert About page to use Bootstrap utility classes and add comprehensive community content --- pages/about.tsx | 1 + pages/index.tsx | 19 +++++++------------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/pages/about.tsx b/pages/about.tsx index b11d5e751..8eaad4728 100644 --- a/pages/about.tsx +++ b/pages/about.tsx @@ -21,6 +21,7 @@ const AboutPage = observer(() => ( freeCodeCamp(简称 FCC)是由美国人 Quincy Larson 发起的开源项目,截止 2018-02-03,在 Github 上获得 29+万 Star(教育类排名第一)。有长达 1600 小时的课程, 并且是基于浏览器、课程免费、证书免费、结合了游戏化闯关的乐趣。FCC 是一个在 160 多个国家和 2000 多个城市的拥有与 1000k+ 开发者的社区。

+ {/* cspell:disable-next-line */} 2016 年 4 月,由 DevEco (晋剑 + Miya)将 FCC 引入中国,并举办了 2000+ 开发者参与的在线全民编程活动,到目前为止,已成功举办了 100+ 场 Coffee & Code / 编程黑客松 / 编程静修日等活动。在 FCC China , 有 20+% 的女性加入到了社区学习、提升编程能力。

diff --git a/pages/index.tsx b/pages/index.tsx index 9964eabbc..894f82ccb 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,5 +1,4 @@ import { observer } from 'mobx-react'; -import { compose, translator } from 'next-ssr-middleware'; import { Button, Col, Container, Row } from 'react-bootstrap'; import { CommunityStats } from '../components/Home/CommunityStats'; @@ -7,7 +6,6 @@ import { LatestBlogs } from '../components/Home/LatestBlogs'; import { Sponsors } from '../components/Home/Sponsors'; import { UpcomingEvents } from '../components/Home/UpcomingEvents'; import { PageHead } from '../components/Layout/PageHead'; -import { i18n, t } from '../models/Translation'; import { ArticleMeta, pageListOf, traverseTree } from './api/core'; import styles from '../styles/Home.module.less'; @@ -19,21 +17,17 @@ interface HomePageProps { export const getStaticProps = async () => { try { - console.log('Starting to fetch data...'); + console.info('Starting to fetch data...'); const [articles, activities, partners] = await Promise.all([ Array.fromAsync(pageListOf('/article/Wiki/_posts/Article/Translation')), Array.fromAsync(pageListOf('/article/Wiki/_posts/Activity')), Array.fromAsync(pageListOf('/article/Wiki/_posts/Partner')) ]); - console.log('Raw articles:', articles); - console.log('Raw activities:', activities); - console.log('Raw partners:', partners); - const latestArticles = articles // .map(root => { // let message = [...traverseTree(root, 'subs')]; - // console.log('123:', root); + // console.info('123:', root); // return message; // }) .flat() @@ -45,12 +39,13 @@ export const getStaticProps = async () => { }) .slice(0, 3); - console.log('Processed latestArticles:', latestArticles); + console.info('Processed latestArticles:', latestArticles); const upcomingEvents = activities .map(root => { let message = [...traverseTree(root, 'subs')] - console.log('aabbcc:', message); + /* cspell:disable-next-line */ + console.info('aabbcc:', message); return message; }) .flat() @@ -66,7 +61,7 @@ export const getStaticProps = async () => { }) .slice(0, 3); - console.log('Processed upcomingEvents:', upcomingEvents); + console.info('Processed upcomingEvents:', upcomingEvents); const sponsors = partners // .map(root => [...traverseTree(root, 'subs')]) @@ -74,7 +69,7 @@ export const getStaticProps = async () => { .filter((sponsor): sponsor is ArticleMeta => 'meta' in sponsor) .slice(0, 3); - console.log('Processed sponsors:', sponsors); + console.info('Processed sponsors:', sponsors); return { props: { latestArticles, upcomingEvents, sponsors }, From 0471d093c102299b67a1b305ef42305824499027 Mon Sep 17 00:00:00 2001 From: dethan3 Date: Thu, 15 May 2025 23:12:41 +0800 Subject: [PATCH 4/8] feat: Improve website design and layout --- components/Home/CommunityStats.tsx | 52 ++++--- components/Home/LatestBlogs.tsx | 62 ++++---- components/Home/Sponsors.tsx | 54 ++++--- components/Home/UpcomingEvents.tsx | 66 ++++---- components/Navigator/MainNavigator.tsx | 7 +- pages/_app.tsx | 37 +++-- pages/about.tsx | 71 +++++++-- pages/api/core.ts | 19 ++- pages/index.tsx | 182 +++++++++++++++------- styles/Home.module.less | 62 -------- styles/globals.less | 205 ++++++++++++++++++++++++- 11 files changed, 553 insertions(+), 264 deletions(-) delete mode 100644 styles/Home.module.less diff --git a/components/Home/CommunityStats.tsx b/components/Home/CommunityStats.tsx index 8bef15924..56aae799b 100644 --- a/components/Home/CommunityStats.tsx +++ b/components/Home/CommunityStats.tsx @@ -1,26 +1,32 @@ -import { Card,Col, Container, Row } from 'react-bootstrap'; +import { Card, Col, Container, Row } from 'react-bootstrap'; export const CommunityStats = () => ( - -

- 社区数据 -

- - {[ - { number: '1000+', label: '社区成员' }, - { number: '50+', label: '举办活动' }, - { number: '200+', label: '技术文章' }, - { number: '30+', label: '开源项目' }, - ].map(({ number, label }) => ( - - - -

{number}

-

{label}

-
-
- - ))} -
-
+
+ +

社区数据

+
+
+
+ + {[ + { number: '1000+', label: '社区成员' }, + { number: '50+', label: '举办活动' }, + { number: '200+', label: '技术文章' }, + { number: '30+', label: '开源项目' }, + ].map(({ number, label }) => ( + + + +

{number}

+

{label}

+
+
+ + ))} +
+ +
); diff --git a/components/Home/LatestBlogs.tsx b/components/Home/LatestBlogs.tsx index 30e092bcb..648345231 100644 --- a/components/Home/LatestBlogs.tsx +++ b/components/Home/LatestBlogs.tsx @@ -1,36 +1,46 @@ import Link from 'next/link'; +import { FC } from 'react'; import { Button, Card, Col, Container, Row } from 'react-bootstrap'; + import { ArticleMeta } from '../../pages/api/core'; interface LatestBlogsProps { articles: ArticleMeta[]; } -export const LatestBlogs: React.FC = ({ articles }) => ( - -

最新博客文章

- - {articles.map((article) => ( - - - - {article.name} - - 发布日期: {article.meta?.date || '未知日期'} - - - 阅读文章 - - - - - ))} - +export const LatestBlogs: FC = ({ articles }) => ( +
+ +

最新博客文章

+
+
+
+ + {articles.map(({ name, meta, path }) => ( + + + + {name} + + 发布日期: {meta?.date || '未知日期'} + + + 阅读文章 + + + + + ))} + -
- -
- +
+ +
+ +
); diff --git a/components/Home/Sponsors.tsx b/components/Home/Sponsors.tsx index 5754f9401..a64719e89 100644 --- a/components/Home/Sponsors.tsx +++ b/components/Home/Sponsors.tsx @@ -1,30 +1,42 @@ +import { FC } from 'react'; import { Button, Card, Col, Container, Row } from 'react-bootstrap'; + import { ArticleMeta } from '../../pages/api/core'; interface SponsorsProps { sponsors: ArticleMeta[]; } -export const Sponsors: React.FC = ({ sponsors }) => ( - -

赞助商与合作伙伴

- - {sponsors.map((sponsor) => ( - - - - {sponsor.name} - {sponsor.meta?.description || '暂无描述'} - - - - ))} - +export const Sponsors: FC = ({ sponsors }) => ( +
+ +

赞助商与合作伙伴

+
+
+
+ + {sponsors.map(({ name, meta }) => ( + + + + {name} + + {meta?.description || '暂无描述'} + + + + + ))} + -
- -
- +
+ +
+ +
); diff --git a/components/Home/UpcomingEvents.tsx b/components/Home/UpcomingEvents.tsx index e8b48f76a..d93e4aa5d 100644 --- a/components/Home/UpcomingEvents.tsx +++ b/components/Home/UpcomingEvents.tsx @@ -1,36 +1,50 @@ import Link from 'next/link'; +import { FC } from 'react'; import { Button, Card, Col, Container, Row } from 'react-bootstrap'; + import { ArticleMeta } from '../../pages/api/core'; interface UpcomingEventsProps { events: ArticleMeta[]; } -export const UpcomingEvents: React.FC = ({ events }) => ( - -

往期活动

- - {events.map((event) => ( - - - - {event.meta?.title} - 时间: {event.meta?.start || 'void 0'} - 地点: {event.meta?.address || 'void 0'} - {/* TODO: 无 Path 不渲染 */} - - 查看详情 - - - - - ))} - +export const UpcomingEvents: FC = ({ events }) => ( +
+ +

近期活动

+
+
+
+ + {events.map(({ name, meta, path }) => ( + + + + {name} + + 时间: {meta?.start || 'void 0'} + + + 地点: {meta?.address || 'void 0'} + + + + 查看详情 + + + + + ))} + -
- -
- +
+ +
+ +
); diff --git a/components/Navigator/MainNavigator.tsx b/components/Navigator/MainNavigator.tsx index 02ca0bb51..412b30e6a 100644 --- a/components/Navigator/MainNavigator.tsx +++ b/components/Navigator/MainNavigator.tsx @@ -10,7 +10,7 @@ const LanguageMenu = dynamic(import('./LanguageMenu'), { ssr: false }); const Name = process.env.NEXT_PUBLIC_SITE_NAME || ''; export const MainNavigator: FC = observer(() => ( - + {Name} @@ -26,7 +26,10 @@ export const MainNavigator: FC = observer(() => ( {t('about')} - + {t('source_code')} diff --git a/pages/_app.tsx b/pages/_app.tsx index bbb3d891c..02684c359 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -6,7 +6,7 @@ import { enableStaticRendering, observer } from 'mobx-react'; import type { AppProps } from 'next/app'; import Head from 'next/head'; import { FC } from 'react'; -import { Image } from 'react-bootstrap'; +import { Container, Image } from 'react-bootstrap'; import { MDXLayout } from '../components/Layout/MDXLayout'; import { MainNavigator } from '../components/Navigator/MainNavigator'; @@ -39,23 +39,32 @@ const AppShell: FC = observer(({ Component, pageProps, router }) => ( ) : ( -
+
)} -
- - {t('powered_by')} - - Vercel Logo - - + )); diff --git a/pages/about.tsx b/pages/about.tsx index 8eaad4728..6a4036a23 100644 --- a/pages/about.tsx +++ b/pages/about.tsx @@ -1,28 +1,37 @@ import { observer } from 'mobx-react'; import { compose, translator } from 'next-ssr-middleware'; import { Container, Table } from 'react-bootstrap'; + import { PageHead } from '../components/Layout/PageHead'; import { i18n, t } from '../models/Translation'; export const getServerSideProps = compose(translator(i18n)); const AboutPage = observer(() => ( - +

{t('about_us')}

- FCC 成都社区, 成立于 2016 年 6 月,是一个非营利性的公益性技术社区,是由一群热血有志青年爱好者,利用个人业余休息时间组建而成的技术社区,目的是为了搭建一个友好的交流、学习、互助的社区,帮助成都市众多的开发者,技术爱好者提升个人技术能力。社区致力于做西南地区首个有温度与情怀的技术社区,鼓励人人皆可编程实现个人梦想。 + fCC 成都社区, 成立于 2016 年 6 + 月,是一个非营利性的公益性技术社区,是由一群热血有志青年爱好者,利用个人业余休息时间组建而成的技术社区,目的是为了搭建一个友好的交流、学习、互助的社区,帮助成都市众多的开发者,技术爱好者提升个人技术能力。社区致力于做西南地区首个有温度与情怀的技术社区,鼓励人人皆可编程实现个人梦想。

什么是 FCC

- freeCodeCamp(简称 FCC)是由美国人 Quincy Larson 发起的开源项目,截止 2018-02-03,在 Github 上获得 29+万 Star(教育类排名第一)。有长达 1600 小时的课程, 并且是基于浏览器、课程免费、证书免费、结合了游戏化闯关的乐趣。FCC 是一个在 160 多个国家和 2000 多个城市的拥有与 1000k+ 开发者的社区。 + freeCodeCamp(简称 FCC)是由美国人 Quincy Larson 发起的开源项目,截止 + 2018-02-03,在 Github 上获得 29+万 Star(教育类排名第一)。有长达 1600 + 小时的课程, + 并且是基于浏览器、课程免费、证书免费、结合了游戏化闯关的乐趣。FCC + 是一个在 160 多个国家和 2000 多个城市的拥有与 1000k+ 开发者的社区。

{/* cspell:disable-next-line */} - 2016 年 4 月,由 DevEco (晋剑 + Miya)将 FCC 引入中国,并举办了 2000+ 开发者参与的在线全民编程活动,到目前为止,已成功举办了 100+ 场 Coffee & Code / 编程黑客松 / 编程静修日等活动。在 FCC China , 有 20+% 的女性加入到了社区学习、提升编程能力。 + 2016 年 4 月,由 DevEco (晋剑 + Miya)将 FCC 引入中国,并举办了 2000+ + 开发者参与的在线全民编程活动,到目前为止,已成功举办了 100+ 场 Coffee & + Code / 编程黑客松 / 编程静修日等活动。在 FCC China , 有 20+% + 的女性加入到了社区学习、提升编程能力。

@@ -39,7 +48,7 @@ const AboutPage = observer(() => (
  • 2017 成都首届 Web 前端交流大会
  • 新耀杯 Code for City 黑客松大赛
  • - +

    历史活动

    @@ -85,19 +94,27 @@ const AboutPage = observer(() => (
    -

    显示部分历史活动,完整列表请参考原文档

    +

    + 显示部分历史活动,完整列表请参考原文档 +

    为什么是 FCC 成都社区

    - 在成都众多的技术大会、技术分享活动当中,很多的活动以技术分享为幌子,做着产品推广与宣传的事情,这导致了成都 IT 圈子技术分享的氛围越来越差,大家参与分享的热情越来越低。 + 在成都众多的技术大会、技术分享活动当中,很多的活动以技术分享为幌子,做着产品推广与宣传的事情,这导致了成都 + IT 圈子技术分享的氛围越来越差,大家参与分享的热情越来越低。

    - FCC 成都社区的众多小伙伴,一致认为是时候为这座热爱的城市做一份自己的贡献了,社区提出所有活动全部免费参加、嘉宾分享内容中广告零容忍,成立嘉宾分享内容审查团队,确保每一次分享都是 100% 的干货。 + FCC + 成都社区的众多小伙伴,一致认为是时候为这座热爱的城市做一份自己的贡献了,社区提出所有活动全部免费参加、嘉宾分享内容中广告零容忍,成立嘉宾分享内容审查团队,确保每一次分享都是 + 100% 的干货。

    - FCC 成都社区的小伙伴们一直明白社区所肩负的使命,带动成都 IT 圈子技术交流的氛围,让更多的技术牛人帮助到更多的开发者,让成都成为全国 IT 行业的先锋,让成都吸引更多 IT 人才蓉漂。进入更多的校园普及更多的次的编程知识,倡导人人皆可编程,让成都这座城市未来充满无限可能。 + FCC 成都社区的小伙伴们一直明白社区所肩负的使命,带动成都 IT + 圈子技术交流的氛围,让更多的技术牛人帮助到更多的开发者,让成都成为全国 + IT 行业的先锋,让成都吸引更多 IT + 人才蓉漂。进入更多的校园普及更多的次的编程知识,倡导人人皆可编程,让成都这座城市未来充满无限可能。

    @@ -105,10 +122,22 @@ const AboutPage = observer(() => (

    FCC 成都社区规划

    1. 走进更多校园,普及人人皆可编程思想帮助更多的孩子们。
    2. -
    3. 继续坚持做好两周一次的【Coffee and Code】的结对编程活动、编程道场活动,一对一指导开发者提升个人技术能力。
    4. -
    5. 做好季度技术专场活动,让成都众多 IT 公司加入其中进行分享,带动成都 IT 圈子技术分享的热情。
    6. -
    7. 做好成都 Web 前端交流大会,让国内一线技术大咖来到成都,给成都众多开发者带来国内一线开发公司的技术心得与经验。
    8. -
    9. 联合成都众多大型 IT 公司,做好编程马拉松活动,让成都的众多开发者进行技术火花的碰撞。
    10. +
    11. + 继续坚持做好两周一次的【Coffee and + Code】的结对编程活动、编程道场活动,一对一指导开发者提升个人技术能力。 +
    12. +
    13. + 做好季度技术专场活动,让成都众多 IT 公司加入其中进行分享,带动成都 IT + 圈子技术分享的热情。 +
    14. +
    15. + 做好成都 Web + 前端交流大会,让国内一线技术大咖来到成都,给成都众多开发者带来国内一线开发公司的技术心得与经验。 +
    16. +
    17. + 联合成都众多大型 IT + 公司,做好编程马拉松活动,让成都的众多开发者进行技术火花的碰撞。 +
    @@ -132,15 +161,21 @@ const AboutPage = observer(() => (

    成都市高新电视台报道

    -

    2017 成都 Web 前端交流大会 (6 分 53 秒处)

    +

    + 2017 成都 Web 前端交流大会 (6 分 53 秒处) +

    -

    四川财富广播 FM94.0 采访

    -

    FCC 成都社区:“人人皆可编程”,以独特的方式为城市带来美好改变

    +

    + 四川财富广播 FM94.0 采访 +

    +

    + FCC 成都社区:“人人皆可编程”,以独特的方式为城市带来美好改变 +

    @@ -148,7 +183,9 @@ const AboutPage = observer(() => (

    四川日报报道

    -

    揭秘“黑客马拉松”:喝 6 瓶红牛、24 小时里只睡 2 小时

    +

    + 揭秘“黑客马拉松”:喝 6 瓶红牛、24 小时里只睡 2 小时 +

    diff --git a/pages/api/core.ts b/pages/api/core.ts index 16ae8a067..4509bb570 100644 --- a/pages/api/core.ts +++ b/pages/api/core.ts @@ -56,15 +56,11 @@ export interface ArticleMeta { const MDX_pattern = /\.mdx?$/; export async function frontMatterOf(path: string) { - try { - const { readFile } = await import('fs/promises'); - const file = await readFile(path, 'utf-8'); - const [, frontMatter] = file.match(/^---[\r\n]([\s\S]+?[\r\n])---/) || []; - return frontMatter ? parse(frontMatter) : null; - } catch (error) { - console.error(`Error reading front matter from ${path}:`, error); - return null; - } + const { readFile } = await import('fs/promises'); + const file = await readFile(path, 'utf-8'); + const [, frontMatter] = file.match(/^---[\r\n]([\s\S]+?[\r\n])---/) || []; + + return frontMatter ? parse(frontMatter) : null; } export async function* pageListOf( @@ -94,7 +90,10 @@ export async function* pageListOf( if (meta) article.meta = meta; yield article; } catch (error) { - console.error(`Error reading front matter for ${node.path}/${node.name}:`, error); + console.error( + `Error reading front matter for ${node.path}/${node.name}:`, + error, + ); } } } else if (node.isDirectory()) { diff --git a/pages/index.tsx b/pages/index.tsx index 894f82ccb..ea429fc3d 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -7,117 +7,187 @@ import { Sponsors } from '../components/Home/Sponsors'; import { UpcomingEvents } from '../components/Home/UpcomingEvents'; import { PageHead } from '../components/Layout/PageHead'; import { ArticleMeta, pageListOf, traverseTree } from './api/core'; -import styles from '../styles/Home.module.less'; interface HomePageProps { latestArticles: ArticleMeta[]; upcomingEvents: ArticleMeta[]; sponsors: ArticleMeta[]; + error?: { + message: string; + stack?: string; + }; } export const getStaticProps = async () => { try { console.info('Starting to fetch data...'); const [articles, activities, partners] = await Promise.all([ - Array.fromAsync(pageListOf('/article/Wiki/_posts/Article/Translation')), + Array.fromAsync(pageListOf('/article/Wiki/_posts/Article')), Array.fromAsync(pageListOf('/article/Wiki/_posts/Activity')), - Array.fromAsync(pageListOf('/article/Wiki/_posts/Partner')) + Array.fromAsync(pageListOf('/article/Wiki/_posts/Partner')), ]); const latestArticles = articles - // .map(root => { - // let message = [...traverseTree(root, 'subs')]; - // console.info('123:', root); - // return message; - // }) + .map(root => { + const message = [...traverseTree(root, 'subs')]; + console.info('123:', root); + + return message; + }) .flat() .filter((article): article is ArticleMeta => 'meta' in article) .sort((a, b) => { const dateA = a.meta?.date ? new Date(a.meta.date).getTime() : 0; const dateB = b.meta?.date ? new Date(b.meta.date).getTime() : 0; - return dateB - dateA; // Sort in descending order (newest first) + + return dateB - dateA; }) .slice(0, 3); - + console.info('Processed latestArticles:', latestArticles); const upcomingEvents = activities - .map(root => { - let message = [...traverseTree(root, 'subs')] - /* cspell:disable-next-line */ - console.info('aabbcc:', message); - return message; - }) + .map(root => [...traverseTree(root, 'subs')]) .flat() .filter((event): event is ArticleMeta => 'meta' in event) - // .filter(event => { - // const eventDate = event.meta?.date ? new Date(event.meta.date) : null; - // return eventDate && eventDate > new Date(); // Only keep future events - // }) .sort((a, b) => { const dateA = a.meta?.date ? new Date(a.meta.date).getTime() : 0; const dateB = b.meta?.date ? new Date(b.meta.date).getTime() : 0; - return dateB - dateA; // Sort in ascending order (nearest future first) + + return dateB - dateA; }) .slice(0, 3); console.info('Processed upcomingEvents:', upcomingEvents); const sponsors = partners - // .map(root => [...traverseTree(root, 'subs')]) .flat() .filter((sponsor): sponsor is ArticleMeta => 'meta' in sponsor) .slice(0, 3); console.info('Processed sponsors:', sponsors); - return { + return { props: { latestArticles, upcomingEvents, sponsors }, - revalidate: 3600 // Revalidate every hour + revalidate: 3600, }; } catch (error) { console.error('Error fetching data:', error); + return { props: { latestArticles: [], upcomingEvents: [], - sponsors: [] + sponsors: [], + error: { + message: error instanceof Error ? error.message : String(error), + stack: error instanceof Error ? error.stack : undefined, + }, }, - revalidate: 3600 + revalidate: 3600, }; } }; -const HomePage = observer(({ latestArticles, upcomingEvents, sponsors }: HomePageProps) => ( - - - - - -

    freeCodeCamp 成都社区

    -
    -

    - 一个友好的技术社区,致力于交流、学习和互助,帮助成都的开发者和技术爱好者提升个人技术能力。 -

    -
    - - +const HomePage = observer( + ({ latestArticles, upcomingEvents, sponsors, error }: HomePageProps) => ( +
    + + + {error ? ( +
    + + + +
    +

    加载数据时发生错误

    +

    {error.message}

    + {process.env.NODE_ENV !== 'production' && error.stack && ( +
    {error.stack}
    + )} +
    + +
    +
    - - - - - - - - - - - -)); + ) : ( + <> +
    + + + +

    + freeCodeCamp 成都社区 +

    +

    + 一个友好的技术社区,致力于交流、学习和互助,帮助成都的开发者和技术爱好者提升个人技术能力。 +

    +
    + + +
    + + +
    + FreeCodeCamp Chengdu +
    + +
    +
    +
    + +
    + + + +
    + +
    + + + +
    + +
    + + + +
    + +
    + + + +
    + + )} +
    + ), +); export default HomePage; diff --git a/styles/Home.module.less b/styles/Home.module.less deleted file mode 100644 index 43e89d03f..000000000 --- a/styles/Home.module.less +++ /dev/null @@ -1,62 +0,0 @@ -.main { - padding: 4rem 0; - min-height: 100vh; -} - -.imagePlaceholder { - display: flex; - justify-content: center; - align-items: center; - box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); - border-radius: 16px; - background: #f0f0f0; - width: 80%; - max-width: 400px; - height: 300px; -} - -.title { - font-size: 4rem; - line-height: 1.15; - a { - &:hover, - &:focus, - &:active { - text-decoration: underline; - } - } -} -.description { - margin: 4rem 0; - line-height: 1.5; -} - -.code { - padding: 0.75rem; - font-size: 1.1rem; - font-family: - Menlo, - Monaco, - Lucida Console, - Liberation Mono, - DejaVu Sans Mono, - Bitstream Vera Sans Mono, - Courier New, - monospace; -} - -.card { - transition: - color 0.15s ease, - border-color 0.15s ease; - color: inherit; - &:hover, - &:focus, - &:active { - border-color: #0070f3; - color: #0070f3; - } - p { - line-height: 1.5; - } -} diff --git a/styles/globals.less b/styles/globals.less index 123889418..e1f7ba6fd 100644 --- a/styles/globals.less +++ b/styles/globals.less @@ -1,11 +1,15 @@ +:root { + --fcc-primary: #0a0a23; + --fcc-secondary: #1b1b32; + --fcc-accent: #f1be32; + --fcc-light: #f5f6f7; +} + html, body { margin: 0; - background-image: linear-gradient( - 150deg, - #028dfa 60%, - #0ee6e6 100% - ) !important; + background: linear-gradient(135deg, #028dfa 0%, #ffffff 50%, #0ee6e6 100%); + background-attachment: fixed; padding: 0; font-family: -apple-system, @@ -21,6 +25,12 @@ body { sans-serif; } +body { + display: flex; + flex-direction: column; + min-height: 100vh; +} + a { color: inherit; text-decoration: none; @@ -30,6 +40,106 @@ a { box-sizing: border-box; } +main { + flex: 1; +} + +.hero-section { + display: flex; + align-items: center; + margin: 0; + background: linear-gradient(135deg, #028dfa 0%, #ffffff 50%, #0ee6e6 100%); + padding: 5rem 0; + width: 100%; + min-height: 80vh; + color: var(--fcc-primary); +} + +.section-wrapper { + margin: 0; + padding: 3rem 0; + width: 100%; +} + +.section-wrapper-white { + background-color: white; +} + +.section-wrapper-gray { + background-color: rgb(248, 249, 250); +} + +.hero-dark-text { + color: var(--fcc-primary); +} + +.accent-text { + color: #0a0a23; + font-weight: bold; +} + +.btn-primary { + border-color: #028dfa; + background-color: #028dfa; + color: white; + font-weight: 600; +} + +.btn-primary:hover { + border-color: #0275d8; + background-color: #0275d8; + color: white; +} + +.btn-outline-primary { + border-color: #028dfa; + color: #028dfa; +} + +.btn-outline-primary:hover { + background-color: #028dfa; + color: white; +} + +.card { + transition: + transform 0.3s ease, + box-shadow 0.3s ease; +} + +.card:hover { + transform: translateY(-5px); + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); +} + +.section-heading { + position: relative; + margin-bottom: 30px; + padding-bottom: 15px; +} + +.section-heading::after { + position: absolute; + bottom: 0; + left: 0; + background-color: var(--fcc-accent); + width: 50px; + height: 3px; + content: ''; +} + +.section-heading.text-center::after { + left: 50%; + transform: translateX(-50%); +} + +/* Responsive adjustments for navbar buttons */ +@media (max-width: 991.98px) { + .navbar .btn { + margin-top: 0.5rem; + } +} + [contenteditable='true'], article { img { @@ -49,6 +159,87 @@ div:has(.next-error-h1) { } :root { - --bs-primary: #000000; - --bs-primary-rgb: 2, 141, 250; + --bs-primary: var(--fcc-accent); + --bs-primary-rgb: 241, 190, 50; +} + +/* Custom navbar styling */ +.navbar.bg-light { + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + background-color: white !important; + padding-top: 0.425rem !important; + padding-bottom: 0.425rem !important; + min-height: auto !important; +} + +.navbar .nav-link { + position: relative; + transition: color 0.3s ease; + padding-top: 0.375rem !important; + padding-bottom: 0.375rem !important; + color: #000000 !important; + font-weight: 500; + font-size: 0.9rem; +} + +.navbar .nav-link:hover { + color: #028dfa !important; +} + +.navbar .nav-link::after { + position: absolute; + bottom: 0; + left: 50%; + transform: translateX(-50%); + transition: all 0.3s ease; + background-color: #028dfa; + width: 0; + height: 2px; + content: ''; +} + +.navbar .nav-link:hover::after { + width: 80%; +} + +.navbar .nav-link.active { + color: #028dfa !important; +} + +.navbar .nav-link.active::after { + width: 80%; +} + +.navbar .navbar-brand { + padding-top: 0.375rem !important; + padding-bottom: 0.375rem !important; + color: #000000 !important; + font-weight: 600; + font-size: 1.1rem; +} + +/* Language menu styling */ +.dropdown-toggle.btn { + border-color: #dee2e6 !important; + padding: 0.25rem 0.5rem !important; + min-width: 100px; + color: #000000 !important; + font-size: 0.9rem !important; +} + +.dropdown-menu { + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15); + border-radius: 0.25rem; + background-color: white !important; + min-width: 100px; +} + +.dropdown-menu .dropdown-item { + padding: 0.5rem 1rem; + color: #000000 !important; + font-size: 0.9rem; +} + +.dropdown-menu .dropdown-item:hover { + background-color: #f8f9fa; } From ae7c62592a663f51e274ae66fb2e281d36ca4dd9 Mon Sep 17 00:00:00 2001 From: dethan3 Date: Thu, 5 Jun 2025 02:48:49 +0000 Subject: [PATCH 5/8] refactor: optimize code --- components/Home/CommunityStats.tsx | 15 +- components/Home/LatestBlogs.tsx | 16 +- components/Home/SectionTitle.tsx | 14 ++ components/Home/Sponsors.tsx | 11 +- components/Home/UpcomingEvents.tsx | 11 +- pages/_app.tsx | 35 ++-- pages/about.tsx | 201 +--------------------- pages/community.tsx | 0 pages/index.tsx | 256 ++++++++++++----------------- styles/Home.module.less | 10 ++ styles/globals.less | 255 ++++++++++++++-------------- 11 files changed, 282 insertions(+), 542 deletions(-) create mode 100644 components/Home/SectionTitle.tsx delete mode 100644 pages/community.tsx create mode 100644 styles/Home.module.less diff --git a/components/Home/CommunityStats.tsx b/components/Home/CommunityStats.tsx index 56aae799b..df94e8020 100644 --- a/components/Home/CommunityStats.tsx +++ b/components/Home/CommunityStats.tsx @@ -1,15 +1,10 @@ import { Card, Col, Container, Row } from 'react-bootstrap'; +import { SectionTitle } from './SectionTitle'; export const CommunityStats = () => ( -
    +
    -

    社区数据

    -
    -
    -
    + {[ { number: '1000+', label: '社区成员' }, @@ -20,8 +15,8 @@ export const CommunityStats = () => ( -

    {number}

    -

    {label}

    + {number} +

    {label}

    diff --git a/components/Home/LatestBlogs.tsx b/components/Home/LatestBlogs.tsx index 648345231..a3a7b5491 100644 --- a/components/Home/LatestBlogs.tsx +++ b/components/Home/LatestBlogs.tsx @@ -1,23 +1,17 @@ -import Link from 'next/link'; import { FC } from 'react'; import { Button, Card, Col, Container, Row } from 'react-bootstrap'; import { ArticleMeta } from '../../pages/api/core'; +import { SectionTitle } from './SectionTitle'; interface LatestBlogsProps { articles: ArticleMeta[]; } export const LatestBlogs: FC = ({ articles }) => ( -
    +
    -

    最新博客文章

    -
    -
    -
    + {articles.map(({ name, meta, path }) => ( @@ -27,9 +21,9 @@ export const LatestBlogs: FC = ({ articles }) => ( 发布日期: {meta?.date || '未知日期'} - + diff --git a/components/Home/SectionTitle.tsx b/components/Home/SectionTitle.tsx new file mode 100644 index 000000000..4fa31a853 --- /dev/null +++ b/components/Home/SectionTitle.tsx @@ -0,0 +1,14 @@ +import React, { FC } from 'react'; + +interface SectionTitleProps { + title: string; +} + +export const SectionTitle: FC = ({ title }) => ( + <> +

    {title}

    +
    +
    +
    + +); diff --git a/components/Home/Sponsors.tsx b/components/Home/Sponsors.tsx index a64719e89..f2622769d 100644 --- a/components/Home/Sponsors.tsx +++ b/components/Home/Sponsors.tsx @@ -2,21 +2,16 @@ import { FC } from 'react'; import { Button, Card, Col, Container, Row } from 'react-bootstrap'; import { ArticleMeta } from '../../pages/api/core'; +import { SectionTitle } from './SectionTitle'; interface SponsorsProps { sponsors: ArticleMeta[]; } export const Sponsors: FC = ({ sponsors }) => ( -
    +
    -

    赞助商与合作伙伴

    -
    -
    -
    + {sponsors.map(({ name, meta }) => ( diff --git a/components/Home/UpcomingEvents.tsx b/components/Home/UpcomingEvents.tsx index d93e4aa5d..b62373b2d 100644 --- a/components/Home/UpcomingEvents.tsx +++ b/components/Home/UpcomingEvents.tsx @@ -3,21 +3,16 @@ import { FC } from 'react'; import { Button, Card, Col, Container, Row } from 'react-bootstrap'; import { ArticleMeta } from '../../pages/api/core'; +import { SectionTitle } from './SectionTitle'; interface UpcomingEventsProps { events: ArticleMeta[]; } export const UpcomingEvents: FC = ({ events }) => ( -
    +
    -

    近期活动

    -
    -
    -
    + {events.map(({ name, meta, path }) => ( diff --git a/pages/_app.tsx b/pages/_app.tsx index 02684c359..b78b035e8 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -39,31 +39,22 @@ const AppShell: FC = observer(({ Component, pageProps, router }) => ( ) : ( -
    - -
    + )} diff --git a/pages/about.tsx b/pages/about.tsx index 6a4036a23..7c9afca5c 100644 --- a/pages/about.tsx +++ b/pages/about.tsx @@ -1,197 +1,12 @@ -import { observer } from 'mobx-react'; -import { compose, translator } from 'next-ssr-middleware'; -import { Container, Table } from 'react-bootstrap'; +import { GetServerSideProps } from 'next'; -import { PageHead } from '../components/Layout/PageHead'; -import { i18n, t } from '../models/Translation'; +export const getServerSideProps: GetServerSideProps = async () => ({ + redirect: { + destination: '/article/Wiki/_posts/Profile/about', + permanent: false, + }, + }); -export const getServerSideProps = compose(translator(i18n)); - -const AboutPage = observer(() => ( - - - -

    {t('about_us')}

    -

    - fCC 成都社区, 成立于 2016 年 6 - 月,是一个非营利性的公益性技术社区,是由一群热血有志青年爱好者,利用个人业余休息时间组建而成的技术社区,目的是为了搭建一个友好的交流、学习、互助的社区,帮助成都市众多的开发者,技术爱好者提升个人技术能力。社区致力于做西南地区首个有温度与情怀的技术社区,鼓励人人皆可编程实现个人梦想。 -

    - -
    -

    什么是 FCC

    -

    - freeCodeCamp(简称 FCC)是由美国人 Quincy Larson 发起的开源项目,截止 - 2018-02-03,在 Github 上获得 29+万 Star(教育类排名第一)。有长达 1600 - 小时的课程, - 并且是基于浏览器、课程免费、证书免费、结合了游戏化闯关的乐趣。FCC - 是一个在 160 多个国家和 2000 多个城市的拥有与 1000k+ 开发者的社区。 -

    -

    - {/* cspell:disable-next-line */} - 2016 年 4 月,由 DevEco (晋剑 + Miya)将 FCC 引入中国,并举办了 2000+ - 开发者参与的在线全民编程活动,到目前为止,已成功举办了 100+ 场 Coffee & - Code / 编程黑客松 / 编程静修日等活动。在 FCC China , 有 20+% - 的女性加入到了社区学习、提升编程能力。 -

    -
    - -
    -

    {t('our_mission')}

    -

    让更多人享受编程的乐趣,并改变自己的生活。

    -
    - -
    -

    FCC 成都社区活动

    -

    大型活动

    -
      -
    • FCC 成都社区 React 技术专场交流活动
    • -
    • 2017 成都首届 Web 前端交流大会
    • -
    • 新耀杯 Code for City 黑客松大赛
    • -
    - -

    历史活动

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    序号日期主题形式
    120160609线下活动开启,宣布社区成立编程讨论
    220160703携手编程-成都社区主页初版动手编程
    320160911结对编程的理念个人分享 + 结对编程
    420161106Console 的九大命令 + 学习路线分享个人分享
    520161119Git 的使用与个人简历制作分享 + 编程
    -
    -

    - 显示部分历史活动,完整列表请参考原文档 -

    -
    - -
    -

    为什么是 FCC 成都社区

    -

    - 在成都众多的技术大会、技术分享活动当中,很多的活动以技术分享为幌子,做着产品推广与宣传的事情,这导致了成都 - IT 圈子技术分享的氛围越来越差,大家参与分享的热情越来越低。 -

    -

    - FCC - 成都社区的众多小伙伴,一致认为是时候为这座热爱的城市做一份自己的贡献了,社区提出所有活动全部免费参加、嘉宾分享内容中广告零容忍,成立嘉宾分享内容审查团队,确保每一次分享都是 - 100% 的干货。 -

    -

    - FCC 成都社区的小伙伴们一直明白社区所肩负的使命,带动成都 IT - 圈子技术交流的氛围,让更多的技术牛人帮助到更多的开发者,让成都成为全国 - IT 行业的先锋,让成都吸引更多 IT - 人才蓉漂。进入更多的校园普及更多的次的编程知识,倡导人人皆可编程,让成都这座城市未来充满无限可能。 -

    -
    - -
    -

    FCC 成都社区规划

    -
      -
    1. 走进更多校园,普及人人皆可编程思想帮助更多的孩子们。
    2. -
    3. - 继续坚持做好两周一次的【Coffee and - Code】的结对编程活动、编程道场活动,一对一指导开发者提升个人技术能力。 -
    4. -
    5. - 做好季度技术专场活动,让成都众多 IT 公司加入其中进行分享,带动成都 IT - 圈子技术分享的热情。 -
    6. -
    7. - 做好成都 Web - 前端交流大会,让国内一线技术大咖来到成都,给成都众多开发者带来国内一线开发公司的技术心得与经验。 -
    8. -
    9. - 联合成都众多大型 IT - 公司,做好编程马拉松活动,让成都的众多开发者进行技术火花的碰撞。 -
    10. -
    -
    - -
    -

    {t('our_team')}

    -

    。。。

    -
    - -
    -

    媒体报道

    -
    -
    -
    -
    -

    四川电视台报道

    -

    四川电视台黑客松报道

    -
    -
    -
    -
    -
    -
    -

    成都市高新电视台报道

    -

    - 2017 成都 Web 前端交流大会 (6 分 53 秒处) -

    -
    -
    -
    -
    -
    -
    -

    - 四川财富广播 FM94.0 采访 -

    -

    - FCC 成都社区:“人人皆可编程”,以独特的方式为城市带来美好改变 -

    -
    -
    -
    -
    -
    -
    -

    四川日报报道

    -

    - 揭秘“黑客马拉松”:喝 6 瓶红牛、24 小时里只睡 2 小时 -

    -
    -
    -
    -
    -
    -
    -)); +const AboutPage = () => null; export default AboutPage; diff --git a/pages/community.tsx b/pages/community.tsx deleted file mode 100644 index e69de29bb..000000000 diff --git a/pages/index.tsx b/pages/index.tsx index ea429fc3d..d1bb4769f 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,11 +1,13 @@ import { observer } from 'mobx-react'; import { Button, Col, Container, Row } from 'react-bootstrap'; +import Image from 'react-bootstrap/Image'; import { CommunityStats } from '../components/Home/CommunityStats'; import { LatestBlogs } from '../components/Home/LatestBlogs'; import { Sponsors } from '../components/Home/Sponsors'; import { UpcomingEvents } from '../components/Home/UpcomingEvents'; import { PageHead } from '../components/Layout/PageHead'; +import styles from '../styles/Home.module.less'; import { ArticleMeta, pageListOf, traverseTree } from './api/core'; interface HomePageProps { @@ -19,173 +21,117 @@ interface HomePageProps { } export const getStaticProps = async () => { - try { - console.info('Starting to fetch data...'); - const [articles, activities, partners] = await Promise.all([ - Array.fromAsync(pageListOf('/article/Wiki/_posts/Article')), - Array.fromAsync(pageListOf('/article/Wiki/_posts/Activity')), - Array.fromAsync(pageListOf('/article/Wiki/_posts/Partner')), - ]); - - const latestArticles = articles - .map(root => { - const message = [...traverseTree(root, 'subs')]; - console.info('123:', root); - - return message; - }) - .flat() - .filter((article): article is ArticleMeta => 'meta' in article) - .sort((a, b) => { - const dateA = a.meta?.date ? new Date(a.meta.date).getTime() : 0; - const dateB = b.meta?.date ? new Date(b.meta.date).getTime() : 0; - - return dateB - dateA; - }) - .slice(0, 3); - - console.info('Processed latestArticles:', latestArticles); - - const upcomingEvents = activities - .map(root => [...traverseTree(root, 'subs')]) - .flat() - .filter((event): event is ArticleMeta => 'meta' in event) - .sort((a, b) => { - const dateA = a.meta?.date ? new Date(a.meta.date).getTime() : 0; - const dateB = b.meta?.date ? new Date(b.meta.date).getTime() : 0; - - return dateB - dateA; - }) - .slice(0, 3); - - console.info('Processed upcomingEvents:', upcomingEvents); - - const sponsors = partners - .flat() - .filter((sponsor): sponsor is ArticleMeta => 'meta' in sponsor) - .slice(0, 3); - - console.info('Processed sponsors:', sponsors); - - return { - props: { latestArticles, upcomingEvents, sponsors }, - revalidate: 3600, - }; - } catch (error) { - console.error('Error fetching data:', error); - - return { - props: { - latestArticles: [], - upcomingEvents: [], - sponsors: [], - error: { - message: error instanceof Error ? error.message : String(error), - stack: error instanceof Error ? error.stack : undefined, - }, - }, - revalidate: 3600, - }; - } + console.info('Starting to fetch data...'); + const [articles, activities, partners] = await Promise.all([ + Array.fromAsync(pageListOf('/article/Wiki/_posts/Article')), + Array.fromAsync(pageListOf('/article/Wiki/_posts/Activity')), + Array.fromAsync(pageListOf('/article/Wiki/_posts/Partner')), + ]); + + const latestArticles = articles + .map(root => { + const message = [...traverseTree(root, 'subs')]; + console.info('123:', root); + + return message; + }) + .flat() + .filter((article): article is ArticleMeta => 'meta' in article) + .sort((a, b) => { + const dateA = a.meta?.date ? new Date(a.meta.date).getTime() : 0; + const dateB = b.meta?.date ? new Date(b.meta.date).getTime() : 0; + + return dateB - dateA; + }) + .slice(0, 3); + + console.info('Processed latestArticles:', latestArticles); + + const upcomingEvents = activities + .map(root => [...traverseTree(root, 'subs')]) + .flat() + .filter((event): event is ArticleMeta => 'meta' in event) + .sort((a, b) => { + const dateA = a.meta?.date ? new Date(a.meta.date).getTime() : 0; + const dateB = b.meta?.date ? new Date(b.meta.date).getTime() : 0; + + return dateB - dateA; + }) + .slice(0, 3); + + console.info('Processed upcomingEvents:', upcomingEvents); + + const sponsors = partners + .flat() + .filter((sponsor): sponsor is ArticleMeta => 'meta' in sponsor) + .slice(0, 6); + + console.info('Processed sponsors:', sponsors); + + return { + props: { latestArticles, upcomingEvents, sponsors }, + revalidate: 3600, + }; }; const HomePage = observer( ({ latestArticles, upcomingEvents, sponsors, error }: HomePageProps) => (
    - - {error ? ( -
    + <> +
    - - -
    -

    加载数据时发生错误

    -

    {error.message}

    - {process.env.NODE_ENV !== 'production' && error.stack && ( -
    {error.stack}
    - )} + + +

    + freeCodeCamp 成都社区 +

    +

    + 一个友好的技术社区,致力于交流、学习和互助,帮助成都的开发者和技术爱好者提升个人技术能力。 +

    +
    + + +
    + + +
    + freeCodeCamp Chengdu
    - ) : ( - <> -
    - - - -

    - freeCodeCamp 成都社区 -

    -

    - 一个友好的技术社区,致力于交流、学习和互助,帮助成都的开发者和技术爱好者提升个人技术能力。 -

    -
    - - -
    - - -
    - FreeCodeCamp Chengdu -
    - -
    -
    -
    - -
    - - - -
    - -
    - - - -
    - -
    - - - -
    - -
    - - - -
    - - )} + + + + + + + +
    ), ); diff --git a/styles/Home.module.less b/styles/Home.module.less new file mode 100644 index 000000000..f80ade69f --- /dev/null +++ b/styles/Home.module.less @@ -0,0 +1,10 @@ +.hero { + display: flex; + align-items: center; + margin: 0; + background: linear-gradient(135deg, #028dfa 0%, #ffffff 50%, #0ee6e6 100%); + padding: 5rem 0; + width: 100%; + min-height: 80vh; + color: var(--fcc-primary); +} diff --git a/styles/globals.less b/styles/globals.less index e1f7ba6fd..66a3e2046 100644 --- a/styles/globals.less +++ b/styles/globals.less @@ -3,6 +3,9 @@ --fcc-secondary: #1b1b32; --fcc-accent: #f1be32; --fcc-light: #f5f6f7; + + --bs-primary: var(--fcc-accent); + --bs-primary-rgb: 241, 190, 50; } html, @@ -40,33 +43,13 @@ a { box-sizing: border-box; } -main { - flex: 1; -} - -.hero-section { - display: flex; - align-items: center; - margin: 0; - background: linear-gradient(135deg, #028dfa 0%, #ffffff 50%, #0ee6e6 100%); - padding: 5rem 0; - width: 100%; - min-height: 80vh; +.hero-dark-text { color: var(--fcc-primary); } -.section-wrapper { - margin: 0; - padding: 3rem 0; - width: 100%; -} - -.section-wrapper-white { - background-color: white; -} - -.section-wrapper-gray { - background-color: rgb(248, 249, 250); +.accent-text { + color: #0a0a23; + font-weight: bold; } .hero-dark-text { @@ -78,59 +61,29 @@ main { font-weight: bold; } -.btn-primary { - border-color: #028dfa; - background-color: #028dfa; - color: white; - font-weight: 600; -} - -.btn-primary:hover { - border-color: #0275d8; - background-color: #0275d8; - color: white; -} - -.btn-outline-primary { - border-color: #028dfa; - color: #028dfa; -} +.btn { + &-primary { + border-color: #028dfa; + background-color: #028dfa; + color: white; + font-weight: 600; -.btn-outline-primary:hover { - background-color: #028dfa; - color: white; -} - -.card { - transition: - transform 0.3s ease, - box-shadow 0.3s ease; -} - -.card:hover { - transform: translateY(-5px); - box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); -} - -.section-heading { - position: relative; - margin-bottom: 30px; - padding-bottom: 15px; -} + &:hover { + border-color: #0275d8; + background-color: #0275d8; + color: white; + } + } -.section-heading::after { - position: absolute; - bottom: 0; - left: 0; - background-color: var(--fcc-accent); - width: 50px; - height: 3px; - content: ''; -} + &-outline-primary { + border-color: #028dfa; + color: #028dfa; -.section-heading.text-center::after { - left: 50%; - transform: translateX(-50%); + &:hover { + background-color: #028dfa; + color: white; + } + } } /* Responsive adjustments for navbar buttons */ @@ -158,64 +111,61 @@ div:has(.next-error-h1) { } } -:root { - --bs-primary: var(--fcc-accent); - --bs-primary-rgb: 241, 190, 50; -} - /* Custom navbar styling */ -.navbar.bg-light { - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - background-color: white !important; - padding-top: 0.425rem !important; - padding-bottom: 0.425rem !important; - min-height: auto !important; -} - -.navbar .nav-link { - position: relative; - transition: color 0.3s ease; - padding-top: 0.375rem !important; - padding-bottom: 0.375rem !important; - color: #000000 !important; - font-weight: 500; - font-size: 0.9rem; -} - -.navbar .nav-link:hover { - color: #028dfa !important; -} - -.navbar .nav-link::after { - position: absolute; - bottom: 0; - left: 50%; - transform: translateX(-50%); - transition: all 0.3s ease; - background-color: #028dfa; - width: 0; - height: 2px; - content: ''; -} - -.navbar .nav-link:hover::after { - width: 80%; -} - -.navbar .nav-link.active { - color: #028dfa !important; -} +.navbar { + &.bg-light { + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + background-color: white !important; + padding-top: 0.425rem !important; + padding-bottom: 0.425rem !important; + min-height: auto !important; + } -.navbar .nav-link.active::after { - width: 80%; -} + .nav-link { + position: relative; + transition: color 0.3s ease; + padding-top: 0.375rem !important; + padding-bottom: 0.375rem !important; + color: #000000 !important; + font-weight: 500; + font-size: 0.9rem; + + &:hover { + color: #028dfa !important; + + &::after { + width: 80%; + } + } + + &::after { + position: absolute; + bottom: 0; + left: 50%; + transform: translateX(-50%); + transition: all 0.3s ease; + background-color: #028dfa; + width: 0; + height: 2px; + content: ''; + } + + &.active { + color: #028dfa !important; + + &::after { + width: 80%; + } + } + } -.navbar .navbar-brand { - padding-top: 0.375rem !important; - padding-bottom: 0.375rem !important; - color: #000000 !important; - font-weight: 600; - font-size: 1.1rem; + .navbar-brand { + padding-top: 0.375rem !important; + padding-bottom: 0.375rem !important; + color: #000000 !important; + font-weight: 600; + font-size: 1.1rem; + } } /* Language menu styling */ @@ -232,14 +182,49 @@ div:has(.next-error-h1) { border-radius: 0.25rem; background-color: white !important; min-width: 100px; + .dropdown-item { + padding: 0.5rem 1rem; + color: #000000 !important; + font-size: 0.9rem; + &:hover { + background-color: #f8f9fa; + } + } } -.dropdown-menu .dropdown-item { - padding: 0.5rem 1rem; - color: #000000 !important; - font-size: 0.9rem; +/* Article content styling */ +.markdown-content { + color: #000000; } -.dropdown-menu .dropdown-item:hover { - background-color: #f8f9fa; +.markdown-content h1, +.markdown-content h2, +.markdown-content h3, +.markdown-content h4, +.markdown-content h5, +.markdown-content h6, +.markdown-content p, +.markdown-content li, +.markdown-content td, +.markdown-content th, +.markdown-content blockquote { + color: #000000; +} + +article { + color: #000000; +} + +article h1, +article h2, +article h3, +article h4, +article h5, +article h6, +article p, +article li, +article td, +article th, +article blockquote { + color: #000000; } From efb40e0513846115d28d81a59b8f37318641aaaa Mon Sep 17 00:00:00 2001 From: dethan3 Date: Wed, 11 Jun 2025 03:33:15 +0000 Subject: [PATCH 6/8] refactor: optimize SectionTitle & redirection to about.md --- components/Home/CommunityStats.tsx | 2 +- components/Home/LatestBlogs.tsx | 2 +- components/Home/SectionTitle.tsx | 10 ++----- components/Home/Sponsors.tsx | 2 +- components/Home/UpcomingEvents.tsx | 6 ++-- components/Navigator/MainNavigator.tsx | 4 ++- next.config.ts | 2 ++ pages/about.tsx | 12 -------- pages/index.tsx | 8 ------ styles/globals.less | 39 ++++++++++---------------- 10 files changed, 29 insertions(+), 58 deletions(-) delete mode 100644 pages/about.tsx diff --git a/components/Home/CommunityStats.tsx b/components/Home/CommunityStats.tsx index df94e8020..5c2fafbee 100644 --- a/components/Home/CommunityStats.tsx +++ b/components/Home/CommunityStats.tsx @@ -4,7 +4,7 @@ import { SectionTitle } from './SectionTitle'; export const CommunityStats = () => (
    - + 社区数据 {[ { number: '1000+', label: '社区成员' }, diff --git a/components/Home/LatestBlogs.tsx b/components/Home/LatestBlogs.tsx index a3a7b5491..9ec605a81 100644 --- a/components/Home/LatestBlogs.tsx +++ b/components/Home/LatestBlogs.tsx @@ -11,7 +11,7 @@ interface LatestBlogsProps { export const LatestBlogs: FC = ({ articles }) => (
    - + 最新文章 {articles.map(({ name, meta, path }) => ( diff --git a/components/Home/SectionTitle.tsx b/components/Home/SectionTitle.tsx index 4fa31a853..99503014d 100644 --- a/components/Home/SectionTitle.tsx +++ b/components/Home/SectionTitle.tsx @@ -1,12 +1,8 @@ -import React, { FC } from 'react'; +import { FC, PropsWithChildren } from 'react'; -interface SectionTitleProps { - title: string; -} - -export const SectionTitle: FC = ({ title }) => ( +export const SectionTitle: FC = ({ children }) => ( <> -

    {title}

    +

    {children}

    diff --git a/components/Home/Sponsors.tsx b/components/Home/Sponsors.tsx index f2622769d..5e23ce1d0 100644 --- a/components/Home/Sponsors.tsx +++ b/components/Home/Sponsors.tsx @@ -11,7 +11,7 @@ interface SponsorsProps { export const Sponsors: FC = ({ sponsors }) => (
    - + 赞助商 {sponsors.map(({ name, meta }) => ( diff --git a/components/Home/UpcomingEvents.tsx b/components/Home/UpcomingEvents.tsx index b62373b2d..ff74a8e3f 100644 --- a/components/Home/UpcomingEvents.tsx +++ b/components/Home/UpcomingEvents.tsx @@ -12,7 +12,7 @@ interface UpcomingEventsProps { export const UpcomingEvents: FC = ({ events }) => (
    - + 近期活动 {events.map(({ name, meta, path }) => ( @@ -20,10 +20,10 @@ export const UpcomingEvents: FC = ({ events }) => ( {name} - 时间: {meta?.start || 'void 0'} + 时间: {meta?.start || 'N/A'} - 地点: {meta?.address || 'void 0'} + 地点: {meta?.address || 'N/A'} diff --git a/components/Navigator/MainNavigator.tsx b/components/Navigator/MainNavigator.tsx index 412b30e6a..7177f2b51 100644 --- a/components/Navigator/MainNavigator.tsx +++ b/components/Navigator/MainNavigator.tsx @@ -24,7 +24,9 @@ export const MainNavigator: FC = observer(() => ( {t('community')} - {t('about')} + + {t('about')} + ({ diff --git a/pages/about.tsx b/pages/about.tsx deleted file mode 100644 index 7c9afca5c..000000000 --- a/pages/about.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { GetServerSideProps } from 'next'; - -export const getServerSideProps: GetServerSideProps = async () => ({ - redirect: { - destination: '/article/Wiki/_posts/Profile/about', - permanent: false, - }, - }); - -const AboutPage = () => null; - -export default AboutPage; diff --git a/pages/index.tsx b/pages/index.tsx index d1bb4769f..2c0d323bf 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -21,7 +21,6 @@ interface HomePageProps { } export const getStaticProps = async () => { - console.info('Starting to fetch data...'); const [articles, activities, partners] = await Promise.all([ Array.fromAsync(pageListOf('/article/Wiki/_posts/Article')), Array.fromAsync(pageListOf('/article/Wiki/_posts/Activity')), @@ -31,7 +30,6 @@ export const getStaticProps = async () => { const latestArticles = articles .map(root => { const message = [...traverseTree(root, 'subs')]; - console.info('123:', root); return message; }) @@ -45,8 +43,6 @@ export const getStaticProps = async () => { }) .slice(0, 3); - console.info('Processed latestArticles:', latestArticles); - const upcomingEvents = activities .map(root => [...traverseTree(root, 'subs')]) .flat() @@ -59,15 +55,11 @@ export const getStaticProps = async () => { }) .slice(0, 3); - console.info('Processed upcomingEvents:', upcomingEvents); - const sponsors = partners .flat() .filter((sponsor): sponsor is ArticleMeta => 'meta' in sponsor) .slice(0, 6); - console.info('Processed sponsors:', sponsors); - return { props: { latestArticles, upcomingEvents, sponsors }, revalidate: 3600, diff --git a/styles/globals.less b/styles/globals.less index 66a3e2046..06af33f80 100644 --- a/styles/globals.less +++ b/styles/globals.less @@ -52,15 +52,6 @@ a { font-weight: bold; } -.hero-dark-text { - color: var(--fcc-primary); -} - -.accent-text { - color: #0a0a23; - font-weight: bold; -} - .btn { &-primary { border-color: #028dfa; @@ -211,20 +202,20 @@ div:has(.next-error-h1) { color: #000000; } -article { - color: #000000; -} - -article h1, -article h2, -article h3, -article h4, -article h5, -article h6, -article p, -article li, -article td, -article th, -article blockquote { +article, +.markdown-content { color: #000000; + h1, + h2, + h3, + h4, + h5, + h6, + p, + li, + td, + th, + blockquote { + color: #000000; + } } From aa978d915d8419564e30ea288054d679dbf2142d Mon Sep 17 00:00:00 2001 From: dethan3 Date: Thu, 12 Jun 2025 00:50:34 +0000 Subject: [PATCH 7/8] restore original next.config.ts and simplify index.tsx code --- next.config.ts | 1 - pages/index.tsx | 98 ++++++++++++++++++++++++------------------------- 2 files changed, 48 insertions(+), 51 deletions(-) diff --git a/next.config.ts b/next.config.ts index 6b6015997..df97a4ea2 100644 --- a/next.config.ts +++ b/next.config.ts @@ -2,7 +2,6 @@ import NextMDX from '@next/mdx'; import { withSentryConfig } from '@sentry/nextjs'; import CopyPlugin from 'copy-webpack-plugin'; import { readdirSync, statSync } from 'fs'; -import type { NextConfig } from 'next'; import setPWA from 'next-pwa'; // @ts-expect-error no official types import withLess from 'next-with-less'; diff --git a/pages/index.tsx b/pages/index.tsx index 2c0d323bf..4ba574906 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -70,60 +70,58 @@ const HomePage = observer( ({ latestArticles, upcomingEvents, sponsors, error }: HomePageProps) => (
    - <> -
    - - - -

    - freeCodeCamp 成都社区 -

    -

    - 一个友好的技术社区,致力于交流、学习和互助,帮助成都的开发者和技术爱好者提升个人技术能力。 -

    -
    - - -
    - - -
    + + + +

    + freeCodeCamp 成都社区 +

    +

    + 一个友好的技术社区,致力于交流、学习和互助,帮助成都的开发者和技术爱好者提升个人技术能力。 +

    +
    +
    - -
    -
    -
    - + 加入社区 + + +
    + + +
    + freeCodeCamp Chengdu +
    + + + +
    + - + - + - - + ), ); From 5a5b58eeba4a4017fd2259f494831b6fdb8fc02b Mon Sep 17 00:00:00 2001 From: TechQuery Date: Sun, 6 Jul 2025 09:14:13 +0800 Subject: [PATCH 8/8] [optimize] simplify Source Code details --- components/Home/CommunityStats.tsx | 11 +++--- components/Home/LatestBlogs.tsx | 20 +++++------ components/Home/SectionTitle.tsx | 1 + components/Home/Sponsors.tsx | 14 ++++---- components/Home/UpcomingEvents.tsx | 26 +++++++------- package.json | 12 +++---- pages/_document.tsx | 4 +-- pages/api/core.ts | 57 ++++++++++++++---------------- pages/article/Wiki | 2 +- pages/index.tsx | 7 ++-- styles/globals.less | 37 +++---------------- 11 files changed, 76 insertions(+), 115 deletions(-) diff --git a/components/Home/CommunityStats.tsx b/components/Home/CommunityStats.tsx index 5c2fafbee..ee79eb40e 100644 --- a/components/Home/CommunityStats.tsx +++ b/components/Home/CommunityStats.tsx @@ -1,10 +1,12 @@ import { Card, Col, Container, Row } from 'react-bootstrap'; import { SectionTitle } from './SectionTitle'; + export const CommunityStats = () => (
    社区数据 + {[ { number: '1000+', label: '社区成员' }, @@ -13,11 +15,10 @@ export const CommunityStats = () => ( { number: '30+', label: '开源项目' }, ].map(({ number, label }) => ( - - - {number} -

    {label}

    -
    + + {number} + +

    {label}

    ))} diff --git a/components/Home/LatestBlogs.tsx b/components/Home/LatestBlogs.tsx index 9ec605a81..55efcb69b 100644 --- a/components/Home/LatestBlogs.tsx +++ b/components/Home/LatestBlogs.tsx @@ -12,24 +12,22 @@ export const LatestBlogs: FC = ({ articles }) => (
    最新文章 + {articles.map(({ name, meta, path }) => ( - - - {name} - - 发布日期: {meta?.date || '未知日期'} - - - + + {name} + + 发布日期: {meta?.date || '未知日期'} + + ))} -