丰富内容
This commit is contained in:
parent
a2bec07322
commit
620e46661f
@ -2,7 +2,7 @@ const Footer = () => {
|
||||
return (
|
||||
<footer className="footer">
|
||||
<div className="footer-content">
|
||||
<p>© 2026 iBoard. 收集和整理经济数据,以经济理论的形式重新组织。</p>
|
||||
<p>© 2026 iBoard. 收集和整理经济数据,以策略为主体重新组织。</p>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
|
||||
17
content/articles/2026-04-01-gdp-analysis.md
Normal file
17
content/articles/2026-04-01-gdp-analysis.md
Normal file
@ -0,0 +1,17 @@
|
||||
---
|
||||
title: GDP增长分析与展望
|
||||
---
|
||||
|
||||
GDP是衡量一个国家经济规模和增长速度的重要指标。本文将分析当前全球主要经济体的GDP增长情况,探讨影响GDP增长的因素,并对未来经济走势进行展望。
|
||||
|
||||
首先,我们来看一下全球GDP增长的整体情况。根据国际货币基金组织(IMF)的最新数据,全球GDP增长率预计将在2026年达到3.5%左右,较2025年有所提升。
|
||||
|
||||
美国作为全球最大的经济体,其GDP增长率预计将保持在2.5%左右。消费、投资和出口是美国经济增长的主要驱动力。美联储的货币政策、政府的财政政策以及地缘政治风险等因素将影响美国经济的表现。
|
||||
|
||||
中国的GDP增长率预计将在5.0%左右。中国经济正在从投资驱动型向消费驱动型转变,科技创新、绿色发展等新动能正在成为经济增长的重要支撑。
|
||||
|
||||
欧元区的GDP增长率预计将在1.8%左右。欧元区经济面临着人口老龄化、结构性改革缓慢等挑战,但也受益于欧洲央行的宽松货币政策和复苏基金的支持。
|
||||
|
||||
影响GDP增长的因素是多方面的,包括货币政策、财政政策、技术进步、人口结构、地缘政治等。在当前全球经济不确定性增加的背景下,各国需要采取适当的政策措施来促进经济增长。
|
||||
|
||||
展望未来,全球经济增长有望保持稳定,但仍面临着诸多挑战。科技创新、数字经济、绿色转型等将成为推动经济增长的重要力量。同时,各国需要加强国际合作,共同应对全球性挑战,如气候变化、贸易保护主义等。
|
||||
19
content/articles/2026-04-02-consumer-trends.md
Normal file
19
content/articles/2026-04-02-consumer-trends.md
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
title: 消费趋势的变化与商业机会
|
||||
---
|
||||
|
||||
消费趋势的变化正在重塑商业格局。本文将分析当前消费市场的主要趋势,探讨这些变化对企业的影响,并为企业提供相应的战略建议。
|
||||
|
||||
首先,我们来看一下消费市场的整体情况。随着经济的发展和居民收入水平的提高,消费结构正在从生存型消费向发展型和享受型消费转变。
|
||||
|
||||
数字化消费已经成为主流。电子商务、移动支付、在线娱乐等数字消费方式正在改变人们的消费习惯。消费者越来越倾向于通过互联网和移动设备进行购物、娱乐和社交。
|
||||
|
||||
健康消费成为新的增长点。消费者对健康食品、健身服务、医疗保健等健康相关产品和服务的需求不断增加。这一趋势在疫情后更加明显,人们对健康的重视程度提高。
|
||||
|
||||
可持续消费理念逐渐深入人心。越来越多的消费者开始关注产品的环保性能,愿意为可持续产品支付溢价。企业的ESG表现也成为消费者选择品牌的重要因素。
|
||||
|
||||
个性化消费需求日益凸显。消费者希望获得个性化的产品和服务,而不是千篇一律的标准化产品。企业需要通过大数据、人工智能等技术来满足消费者的个性化需求。
|
||||
|
||||
这些消费趋势的变化对企业提出了新的挑战和机遇。企业需要调整产品和服务策略,以适应消费者需求的变化。同时,企业也需要利用数字技术来提升运营效率,改善客户体验。
|
||||
|
||||
对于投资者而言,消费趋势的变化也意味着投资机会的转移。需要关注那些能够适应消费趋势变化、具有创新能力的企业。
|
||||
19
content/articles/2026-04-03-tech-innovation.md
Normal file
19
content/articles/2026-04-03-tech-innovation.md
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
title: 科技创新与经济增长
|
||||
---
|
||||
|
||||
科技创新是推动经济增长的重要动力。本文将分析当前科技创新的趋势,探讨其对经济增长的影响,并为政策制定者和投资者提供参考。
|
||||
|
||||
首先,我们来看一下当前科技创新的主要领域。人工智能、区块链、生物技术、可再生能源等领域的技术突破正在改变我们的生活和工作方式。
|
||||
|
||||
人工智能技术的快速发展正在各个行业产生深远影响。从自动驾驶到医疗诊断,从金融服务到制造业,AI正在提高效率,创造新的商业模式。
|
||||
|
||||
区块链技术的应用也在不断扩展。除了加密货币,区块链在供应链管理、数字身份、金融服务等领域的应用正在逐步落地。
|
||||
|
||||
生物技术的进步为医疗健康、农业等领域带来了新的机遇。基因编辑、精准医疗、合成生物学等技术的发展有望解决许多传统医学难以解决的问题。
|
||||
|
||||
可再生能源技术的突破正在加速能源转型。太阳能、风能、储能技术的成本不断下降,为实现碳中和目标提供了技术支持。
|
||||
|
||||
这些科技创新对经济增长的影响是多方面的。它们不仅提高了生产效率,还创造了新的产业和就业机会。同时,科技创新也带来了一些挑战,如就业结构的变化、隐私保护等问题。
|
||||
|
||||
对于政策制定者而言,需要制定有利于科技创新的政策环境,包括加大研发投入、培养创新人才、完善知识产权保护等。对于投资者而言,需要关注科技创新的趋势,寻找具有增长潜力的投资机会。
|
||||
15
content/articles/2026-04-04-global-trade.md
Normal file
15
content/articles/2026-04-04-global-trade.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
title: 全球贸易格局的变化与影响
|
||||
---
|
||||
|
||||
全球贸易格局正在经历深刻的变化。本文将分析当前全球贸易的现状,探讨主要经济体的贸易政策,以及这些变化对全球经济的影响。
|
||||
|
||||
首先,我们来看一下全球贸易的整体情况。尽管贸易保护主义有所抬头,但全球贸易总额仍然保持增长。新兴经济体在全球贸易中的比重不断提高,正在改变传统的贸易格局。
|
||||
|
||||
美国、欧盟、中国等主要经济体的贸易政策对全球贸易产生重要影响。美国的贸易保护主义措施、欧盟的绿色贸易政策、中国的扩大开放政策等,都在塑造着新的贸易规则。
|
||||
|
||||
全球供应链的重构也是当前贸易格局变化的重要特征。出于安全和效率的考虑,许多企业正在调整供应链布局,推动区域化和多元化。
|
||||
|
||||
这些变化对全球经济产生了深远的影响。一方面,贸易格局的调整可能会导致短期的经济波动;另一方面,新的贸易规则和供应链布局也为经济发展带来了新的机遇。
|
||||
|
||||
对于企业和投资者而言,需要密切关注贸易格局的变化,调整战略以适应新的环境。同时,政府也需要制定相应的政策,促进贸易的健康发展。
|
||||
13
content/articles/2026-04-05-interest-rates.md
Normal file
13
content/articles/2026-04-05-interest-rates.md
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
title: 利率走势分析与投资策略
|
||||
---
|
||||
|
||||
近期全球主要经济体的利率走势引起了市场的广泛关注。本文将分析当前利率环境,探讨未来可能的变化趋势,并为投资者提供相应的投资策略建议。
|
||||
|
||||
首先,我们来看一下美联储的货币政策走向。随着通胀压力的缓解,美联储已经开始考虑降息,但步伐可能会比较谨慎。欧洲央行和日本央行也在调整各自的货币政策,以适应经济形势的变化。
|
||||
|
||||
在中国,央行通过调整政策利率和LPR(贷款市场报价利率)来引导市场利率水平。近期LPR的下调反映了货币政策的宽松取向,这将有利于降低企业融资成本,刺激经济增长。
|
||||
|
||||
对于债券投资者而言,利率下行意味着债券价格上涨,这为债券投资提供了机会。但需要注意的是,不同期限的债券对利率变化的敏感度不同,投资者需要根据自己的风险承受能力选择合适的债券品种。
|
||||
|
||||
对于股票投资者而言,利率下行通常有利于估值提升,特别是对成长型股票更为有利。但同时也需要关注经济基本面的变化,选择具有良好成长性和估值合理的股票。
|
||||
13
content/articles/2026-04-06-economic-outlook.md
Normal file
13
content/articles/2026-04-06-economic-outlook.md
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
title: 2026年中国经济展望
|
||||
---
|
||||
|
||||
2026年中国经济将面临诸多挑战与机遇。随着全球经济格局的变化,中国经济正在从高速增长向高质量发展转型。本文将分析当前经济形势,预测未来趋势,并提出相应的政策建议。
|
||||
|
||||
首先,我们来看一下当前的宏观经济指标。GDP增长率、通胀水平、失业率等关键指标都显示中国经济正在稳步复苏。然而,外部环境的不确定性仍然存在,需要密切关注。
|
||||
|
||||
在产业结构方面,数字经济、绿色经济等新兴产业正在成为经济增长的新动力。传统产业的转型升级也在加速,这将为经济可持续发展注入新的活力。
|
||||
|
||||
对于投资者而言,2026年的投资策略需要更加注重长期价值,关注科技创新、消费升级等领域的投资机会。同时,风险管理也变得尤为重要,需要建立多元化的投资组合。
|
||||
|
||||
总的来说,2026年中国经济有望保持稳健增长,但需要应对来自内外部的各种挑战。通过深化改革、扩大开放,中国经济将迎来新的发展机遇。
|
||||
122
package-lock.json
generated
122
package-lock.json
generated
@ -9,6 +9,8 @@
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"gray-matter": "^4.0.3",
|
||||
"marked": "^17.0.6",
|
||||
"next": "^14.2.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
@ -298,6 +300,15 @@
|
||||
"integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"sprintf-js": "~1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/busboy": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
||||
@ -481,18 +492,58 @@
|
||||
"benchmarks"
|
||||
]
|
||||
},
|
||||
"node_modules/esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||
"license": "BSD-2-Clause",
|
||||
"bin": {
|
||||
"esparse": "bin/esparse.js",
|
||||
"esvalidate": "bin/esvalidate.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/eventemitter3": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz",
|
||||
"integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/extend-shallow": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
"integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-extendable": "^0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/gray-matter": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
|
||||
"integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"js-yaml": "^3.13.1",
|
||||
"kind-of": "^6.0.2",
|
||||
"section-matter": "^1.0.0",
|
||||
"strip-bom-string": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/immer": {
|
||||
"version": "10.2.0",
|
||||
"resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz",
|
||||
@ -512,12 +563,43 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extendable": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
|
||||
"integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "3.14.2",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
|
||||
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"node_modules/kind-of": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
||||
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
@ -530,6 +612,18 @@
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/marked": {
|
||||
"version": "17.0.6",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-17.0.6.tgz",
|
||||
"integrity": "sha512-gB0gkNafnonOw0obSTEGZTT86IuhILt2Wfx0mWH/1Au83kybTayroZ/V6nS25mN7u8ASy+5fMhgB3XPNrOZdmA==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"marked": "bin/marked.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
@ -747,6 +841,19 @@
|
||||
"loose-envify": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/section-matter": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
|
||||
"integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"extend-shallow": "^2.0.1",
|
||||
"kind-of": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
@ -756,6 +863,12 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/streamsearch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
||||
@ -764,6 +877,15 @@
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-bom-string": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
|
||||
"integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/styled-jsx": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"dependencies": {
|
||||
"gray-matter": "^4.0.3",
|
||||
"marked": "^17.0.6",
|
||||
"next": "^14.2.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
||||
71
pages/articles/[slug].js
Normal file
71
pages/articles/[slug].js
Normal file
@ -0,0 +1,71 @@
|
||||
import Head from 'next/head'
|
||||
import Navbar from '../../components/Navbar'
|
||||
import Footer from '../../components/Footer'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import matter from 'gray-matter'
|
||||
import { marked } from 'marked'
|
||||
|
||||
export default function Article({ article }) {
|
||||
return (
|
||||
<div className="container">
|
||||
<Head>
|
||||
<title>{article.title} - iBoard</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
|
||||
<Navbar />
|
||||
|
||||
<main>
|
||||
<div className="article-detail">
|
||||
<h1 className="article-detail-title">{article.title}</h1>
|
||||
<div className="article-detail-date">{article.date}</div>
|
||||
<div className="article-detail-content" dangerouslySetInnerHTML={{ __html: article.contentHtml }} />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const articlesDirectory = path.join(process.cwd(), 'content', 'articles')
|
||||
const fileNames = fs.readdirSync(articlesDirectory)
|
||||
|
||||
const paths = fileNames
|
||||
.filter(fileName => fileName.endsWith('.md'))
|
||||
.map(fileName => ({
|
||||
params: { slug: fileName.replace('.md', '') }
|
||||
}))
|
||||
|
||||
return {
|
||||
paths,
|
||||
fallback: false
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticProps({ params }) {
|
||||
const articlesDirectory = path.join(process.cwd(), 'content', 'articles')
|
||||
const fullPath = path.join(articlesDirectory, `${params.slug}.md`)
|
||||
const fileContents = fs.readFileSync(fullPath, 'utf8')
|
||||
const { data, content } = matter(fileContents)
|
||||
|
||||
// 从文件名中提取日期
|
||||
const dateMatch = params.slug.match(/^(\d{4}-\d{2}-\d{2})-/)
|
||||
const date = dateMatch ? dateMatch[1] : ''
|
||||
|
||||
// 将markdown转换为HTML
|
||||
const contentHtml = marked(content)
|
||||
|
||||
return {
|
||||
props: {
|
||||
article: {
|
||||
id: params.slug,
|
||||
title: data.title || params.slug.replace(/\d{4}-\d{2}-\d{2}-/, ''),
|
||||
date,
|
||||
contentHtml
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,8 +2,9 @@ import Head from 'next/head'
|
||||
import Link from 'next/link'
|
||||
import Navbar from '../components/Navbar'
|
||||
import Footer from '../components/Footer'
|
||||
import { getPagedArticles } from '../utils/articleUtils'
|
||||
|
||||
export default function Home() {
|
||||
export default function Home({ articles, totalPages, currentPage }) {
|
||||
return (
|
||||
<div className="container">
|
||||
<Head>
|
||||
@ -24,7 +25,9 @@ export default function Home() {
|
||||
|
||||
<div className="grid">
|
||||
<div className="card">
|
||||
<a href="#articles-section">
|
||||
<h2>经济文章</h2>
|
||||
</a>
|
||||
<p>最新的经济分析和研究文章</p>
|
||||
</div>
|
||||
|
||||
@ -42,9 +45,46 @@ export default function Home() {
|
||||
<p>基于经济理论的数据分析框架</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section id="articles-section" className="articles-section">
|
||||
<h5 className="section-title">看经济</h5>
|
||||
<div className="articles-grid">
|
||||
{articles.map((article) => (
|
||||
<Link key={article.id} href={`/articles/${article.id}`} className="article-card">
|
||||
<div className="article-date">{article.date}</div>
|
||||
<h3 className="article-title">{article.title}</h3>
|
||||
<p className="article-excerpt">{article.excerpt}</p>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{totalPages > 1 && (
|
||||
<div className="pagination">
|
||||
{Array.from({ length: totalPages }, (_, index) => (
|
||||
<Link key={index + 1} href={`/?page=${index + 1}`} className={`page-link ${currentPage === index + 1 ? 'active' : ''}`}>
|
||||
{index + 1}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getServerSideProps({ query }) {
|
||||
const page = parseInt(query.page) || 1
|
||||
const { articles, total, totalPages } = getPagedArticles(page, 5)
|
||||
|
||||
return {
|
||||
props: {
|
||||
articles,
|
||||
total,
|
||||
totalPages,
|
||||
currentPage: page
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,6 +56,12 @@ body {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
/* Global link styles */
|
||||
a {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Main content */
|
||||
main {
|
||||
flex: 1;
|
||||
@ -232,6 +238,151 @@ main {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
/* Articles section */
|
||||
.articles-section {
|
||||
margin-top: 4rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 2rem;
|
||||
color: #333;
|
||||
margin-bottom: 1.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
border-bottom: 2px solid #ddd;
|
||||
}
|
||||
|
||||
.articles-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.article-card {
|
||||
background-color: white;
|
||||
padding: 1.5rem;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.2s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.article-card:hover {
|
||||
background-color: #f9f9f9;
|
||||
transform: translateX(5px);
|
||||
}
|
||||
|
||||
.article-date {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.article-title {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 0.75rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.article-excerpt {
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
/* Pagination */
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 0.5rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.page-link {
|
||||
padding: 0.5rem 1rem;
|
||||
background-color: white;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
color: #333;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.page-link:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.page-link.active {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
border-color: #333;
|
||||
}
|
||||
|
||||
/* Article detail page */
|
||||
.article-detail {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
background-color: white;
|
||||
padding: 2rem;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.article-detail-title {
|
||||
font-size: 2.5rem;
|
||||
color: #333;
|
||||
margin-bottom: 1rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.article-detail-date {
|
||||
font-size: 1rem;
|
||||
color: #666;
|
||||
margin-bottom: 2rem;
|
||||
padding-bottom: 1rem;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.article-detail-content {
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.article-detail-content h1,
|
||||
.article-detail-content h2,
|
||||
.article-detail-content h3,
|
||||
.article-detail-content h4,
|
||||
.article-detail-content h5,
|
||||
.article-detail-content h6 {
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.article-detail-content p {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.article-detail-content ul,
|
||||
.article-detail-content ol {
|
||||
margin-bottom: 1.5rem;
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
.article-detail-content li {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.article-detail-content img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
margin: 2rem 0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.data-layout {
|
||||
flex-direction: column;
|
||||
@ -240,4 +391,16 @@ main {
|
||||
.data-sidebar {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.article-detail {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.article-detail-title {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
52
utils/articleUtils.js
Normal file
52
utils/articleUtils.js
Normal file
@ -0,0 +1,52 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import matter from 'gray-matter'
|
||||
|
||||
export function getArticles() {
|
||||
const articlesDirectory = path.join(process.cwd(), 'content', 'articles')
|
||||
const fileNames = fs.readdirSync(articlesDirectory)
|
||||
|
||||
const articles = fileNames
|
||||
.filter(fileName => fileName.endsWith('.md'))
|
||||
.map(fileName => {
|
||||
const fullPath = path.join(articlesDirectory, fileName)
|
||||
const fileContents = fs.readFileSync(fullPath, 'utf8')
|
||||
const { data, content } = matter(fileContents)
|
||||
|
||||
// 从文件名中提取日期(假设文件名格式为 YYYY-MM-DD-article-title.md)
|
||||
const dateMatch = fileName.match(/^(\d{4}-\d{2}-\d{2})-/)
|
||||
const date = dateMatch ? dateMatch[1] : ''
|
||||
|
||||
// 提取简介(前150个字符)
|
||||
const excerpt = content.substring(0, 150) + '...'
|
||||
|
||||
return {
|
||||
id: fileName.replace('.md', ''),
|
||||
date,
|
||||
title: data.title || fileName.replace(/\d{4}-\d{2}-\d{2}-/, '').replace('.md', ''),
|
||||
excerpt,
|
||||
content
|
||||
}
|
||||
})
|
||||
|
||||
// 按日期排序,最近的优先
|
||||
return articles.sort((a, b) => {
|
||||
if (a.date && b.date) {
|
||||
return new Date(b.date) - new Date(a.date)
|
||||
}
|
||||
return 0
|
||||
})
|
||||
}
|
||||
|
||||
export function getPagedArticles(page = 1, pageSize = 5) {
|
||||
const allArticles = getArticles()
|
||||
const startIndex = (page - 1) * pageSize
|
||||
const endIndex = startIndex + pageSize
|
||||
|
||||
return {
|
||||
articles: allArticles.slice(startIndex, endIndex),
|
||||
total: allArticles.length,
|
||||
totalPages: Math.ceil(allArticles.length / pageSize),
|
||||
currentPage: page
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user