Skip to content

Commit 715281f

Browse files
committed
feat: add twentytwentyfive theme
1 parent 98132ce commit 715281f

File tree

24 files changed

+16250
-272
lines changed

24 files changed

+16250
-272
lines changed

package.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@
22
"name": "@fecommunity/reactpress",
33
"author": "fecommunity",
44
"version": "2.0.0",
5-
"bin": {
6-
"reactpress-server": "./scripts/reactpress-server.js",
7-
"reactpress-client": "./scripts/reactpress-client.js"
8-
},
95
"scripts": {
106
"clean": "pnpm clean:node_modules && pnpm clean:dist",
117
"clean:node_modules": "npx rimraf ./node_modules ./**/node_modules",
@@ -20,6 +16,7 @@
2016
"build:server": "pnpm run --dir ./server build",
2117
"build:client": "pnpm run --dir ./client build",
2218
"build:docs": "pnpm run --dir ./docs build",
19+
"build:toolkit": "pnpm run --dir ./toolkit build",
2320
"deploy:docs": "pnpm run --dir ./docs deploy:surge",
2421
"deploy": "sh scripts/deploy.sh",
2522
"start": "concurrently 'pnpm:start:*'",

pnpm-lock.yaml

Lines changed: 719 additions & 263 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ packages:
99
- 'docs'
1010
# 工具包
1111
- 'toolkit'
12+
# 模板
13+
- 'templates/*'
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Twenty Twenty Five Blog Template
2+
3+
A modern blog template for ReactPress using Next.js Pages Router.
4+
5+
## Features
6+
7+
- Clean, responsive design inspired by WordPress themes
8+
- Server-side rendering for better SEO
9+
- Integration with ReactPress toolkit for API communication
10+
- Pre-built pages:
11+
- Home page with latest articles, categories, and tags
12+
- Article detail page
13+
- Category pages
14+
- Tag pages
15+
- Search functionality
16+
- Custom 404 page
17+
18+
## Getting Started
19+
20+
1. Install dependencies:
21+
```bash
22+
npm install
23+
```
24+
25+
2. Run the development server:
26+
```bash
27+
npm run dev
28+
```
29+
30+
3. Open [http://localhost:3000](http://localhost:3000) in your browser
31+
32+
## Requirements
33+
34+
- Node.js 16.5.0 or later
35+
- A ReactPress backend server running
36+
37+
## Customization
38+
39+
You can customize the template by modifying the components and styles in the `pages` directory.
40+
41+
## Deployment
42+
43+
To deploy your blog, you can use any hosting platform that supports Next.js, such as Vercel, Netlify, or traditional Node.js hosting.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { render, screen } from '@testing-library/react';
2+
import '@testing-library/jest-dom';
3+
import Home from '../pages/index';
4+
5+
// Mock the toolkit API
6+
jest.mock('@fecommunity/reactpress-toolkit', () => ({
7+
api: {
8+
article: {
9+
findAll: jest.fn().mockResolvedValue({ data: [] }),
10+
},
11+
category: {
12+
findAll: jest.fn().mockResolvedValue({ data: [] }),
13+
},
14+
tag: {
15+
findAll: jest.fn().mockResolvedValue({ data: [] }),
16+
},
17+
},
18+
}));
19+
20+
describe('Home Page', () => {
21+
it('renders without crashing', () => {
22+
render(
23+
<Home
24+
initialArticles={[]}
25+
initialCategories={[]}
26+
initialTags={[]}
27+
/>
28+
);
29+
30+
expect(screen.getByText('Latest Articles')).toBeInTheDocument();
31+
});
32+
33+
it('displays navigation links', () => {
34+
render(
35+
<Home
36+
initialArticles={[]}
37+
initialCategories={[]}
38+
initialTags={[]}
39+
/>
40+
);
41+
42+
expect(screen.getByText('Latest Articles')).toBeInTheDocument();
43+
expect(screen.getByText('Categories')).toBeInTheDocument();
44+
expect(screen.getByText('Tags')).toBeInTheDocument();
45+
});
46+
});
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import Link from 'next/link';
2+
import React from 'react';
3+
4+
export default function Footer() {
5+
return (
6+
<footer className="footer">
7+
<div className="footer-content">
8+
<div className="footer-info">
9+
<h3>Twenty Twenty Five</h3>
10+
<p>A modern, minimalist blog template built with ReactPress.</p>
11+
</div>
12+
<div className="footer-links">
13+
<h4>Quick Links</h4>
14+
<ul>
15+
<li><Link href="/"><a>Home</a></Link></li>
16+
<li><Link href="/search"><a>Search</a></Link></li>
17+
<li><Link href="/rss"><a>RSS Feed</a></Link></li>
18+
</ul>
19+
</div>
20+
<div className="footer-credits">
21+
<p>Powered by <a href="https://github.com/fecommunity/reactpress" target="_blank" rel="noopener noreferrer">ReactPress</a></p>
22+
</div>
23+
</div>
24+
25+
<style jsx>{`
26+
.footer {
27+
background: linear-gradient(135deg, #1e1e1e, #111827);
28+
color: #d1d5db;
29+
padding: 4rem 0 2rem;
30+
position: relative;
31+
overflow: hidden;
32+
}
33+
34+
.footer::before {
35+
content: '';
36+
position: absolute;
37+
top: 0;
38+
left: 0;
39+
right: 0;
40+
height: 1px;
41+
background: linear-gradient(90deg, transparent, rgba(59, 130, 246, 0.5), transparent);
42+
}
43+
44+
.footer-content {
45+
max-width: 1200px;
46+
margin: 0 auto;
47+
padding: 0 2rem;
48+
display: grid;
49+
grid-template-columns: 2fr 1fr 1fr;
50+
gap: 2.5rem;
51+
position: relative;
52+
z-index: 2;
53+
}
54+
55+
.footer-info h3,
56+
.footer-links h4 {
57+
color: #fff;
58+
margin: 0 0 1.25rem 0;
59+
font-size: 1.3rem;
60+
font-weight: 700;
61+
letter-spacing: -0.01em;
62+
}
63+
64+
.footer-info p {
65+
margin: 0;
66+
line-height: 1.7;
67+
color: #9ca3af;
68+
}
69+
70+
.footer-links ul {
71+
list-style: none;
72+
padding: 0;
73+
margin: 0;
74+
}
75+
76+
.footer-links li {
77+
margin-bottom: 0.75rem;
78+
}
79+
80+
.footer-links a {
81+
color: #d1d5db;
82+
text-decoration: none;
83+
transition: all 0.2s ease;
84+
display: inline-block;
85+
position: relative;
86+
padding: 0.25rem 0;
87+
}
88+
89+
.footer-links a::after {
90+
content: '';
91+
position: absolute;
92+
bottom: 0;
93+
left: 0;
94+
width: 0;
95+
height: 1px;
96+
background: #3b82f6;
97+
transition: width 0.3s ease;
98+
}
99+
100+
.footer-links a:hover {
101+
color: #3b82f6;
102+
transform: translateX(3px);
103+
}
104+
105+
.footer-links a:hover::after {
106+
width: 100%;
107+
}
108+
109+
.footer-credits {
110+
grid-column: span 3;
111+
text-align: center;
112+
padding-top: 2.5rem;
113+
margin-top: 2.5rem;
114+
border-top: 1px solid #374151;
115+
color: #9ca3af;
116+
}
117+
118+
.footer-credits a {
119+
color: #3b82f6;
120+
text-decoration: none;
121+
font-weight: 500;
122+
}
123+
124+
.footer-credits a:hover {
125+
text-decoration: underline;
126+
}
127+
128+
/* Responsive Design */
129+
@media (max-width: 768px) {
130+
.footer-content {
131+
grid-template-columns: 1fr;
132+
gap: 2rem;
133+
}
134+
135+
.footer-credits {
136+
grid-column: span 1;
137+
}
138+
}
139+
140+
@media (max-width: 480px) {
141+
.footer-content {
142+
padding: 2rem 1rem 1rem;
143+
}
144+
145+
.footer-info h3,
146+
.footer-links h4 {
147+
font-size: 1.1rem;
148+
}
149+
150+
.footer-links ul {
151+
gap: 0.625rem;
152+
}
153+
154+
.footer-links li {
155+
margin-bottom: 0.375rem;
156+
}
157+
158+
.footer-credits {
159+
padding-top: 2rem;
160+
margin-top: 2rem;
161+
}
162+
}
163+
`}</style>
164+
</footer>
165+
);
166+
}

0 commit comments

Comments
 (0)