astro-blog-kit 0.4.1 β 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +151 -86
- package/define-config.ts +147 -100
- package/package.json +1 -1
- package/templates/blog-config.ts.template +43 -22
- package/types.ts +94 -59
package/README.md
CHANGED
|
@@ -6,10 +6,10 @@ A ready-to-use blog system for Astro with WordPress headless support, optional i
|
|
|
6
6
|
|
|
7
7
|
- π **One command setup** β `npx astro-blog-kit init`
|
|
8
8
|
- π **WordPress headless** β connects to WordPress REST API out of the box
|
|
9
|
-
- π¨ **Multiple layouts** β magazine, grid,
|
|
9
|
+
- π¨ **Multiple layouts** β magazine, featured, grid, cards
|
|
10
10
|
- π¬ **Comment system** β with secure proxy to WordPress
|
|
11
11
|
- π **Optional i18n** β multi-language support
|
|
12
|
-
- π¨ **
|
|
12
|
+
- π¨ **Fully themeable** β colors, fonts, hero texts, and UI labels via `blog.config.ts`
|
|
13
13
|
- π¦ **Zero config** β works without any configuration
|
|
14
14
|
|
|
15
15
|
---
|
|
@@ -47,20 +47,13 @@ And will automatically create:
|
|
|
47
47
|
|
|
48
48
|
```js
|
|
49
49
|
// astro.config.mjs
|
|
50
|
-
import { defineConfig } from
|
|
51
|
-
import { blogKit } from
|
|
50
|
+
import { defineConfig } from 'astro/config';
|
|
51
|
+
import { blogKit } from 'astro-blog-kit/integration';
|
|
52
|
+
import config from './blog.config';
|
|
53
|
+
import { toBlogKitConfig } from 'astro-blog-kit';
|
|
52
54
|
|
|
53
55
|
export default defineConfig({
|
|
54
|
-
integrations: [
|
|
55
|
-
blogKit({
|
|
56
|
-
postsPerPage: 5,
|
|
57
|
-
defaultLayout: "magazine",
|
|
58
|
-
theme: {
|
|
59
|
-
accent: "#facc15",
|
|
60
|
-
fontHeading: "Georgia, serif",
|
|
61
|
-
},
|
|
62
|
-
}),
|
|
63
|
-
],
|
|
56
|
+
integrations: [blogKit(toBlogKitConfig(config))],
|
|
64
57
|
});
|
|
65
58
|
```
|
|
66
59
|
|
|
@@ -93,66 +86,157 @@ npm run dev
|
|
|
93
86
|
### `blog.config.ts`
|
|
94
87
|
|
|
95
88
|
```ts
|
|
96
|
-
import { defineBlogConfig } from
|
|
89
|
+
import { defineBlogConfig } from 'astro-blog-kit';
|
|
97
90
|
|
|
98
91
|
export default defineBlogConfig({
|
|
99
|
-
wpUrl:
|
|
92
|
+
wpUrl: import.meta.env.WP_API_URL || 'https://cms.yourdomain.com',
|
|
100
93
|
postsPerPage: 5,
|
|
101
|
-
defaultLayout:
|
|
102
|
-
locale:
|
|
94
|
+
defaultLayout: 'magazine', // 'magazine' | 'grid' | 'featured' | 'cards'
|
|
95
|
+
locale: 'en', // 'en' | 'es'
|
|
96
|
+
|
|
103
97
|
theme: {
|
|
104
|
-
accent:
|
|
105
|
-
background:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
98
|
+
accent: '#facc15',
|
|
99
|
+
background: '#ffffff',
|
|
100
|
+
surface: '#f8f8f8',
|
|
101
|
+
text: '#0a0a0a',
|
|
102
|
+
muted: '#6b7280',
|
|
103
|
+
mutedLight: '#9ca3af',
|
|
104
|
+
border: '#e5e7eb',
|
|
105
|
+
black: '#0a0a0a',
|
|
106
|
+
white: '#ffffff',
|
|
107
|
+
fontHeading: 'Georgia, serif',
|
|
108
|
+
fontBody: 'system-ui, sans-serif',
|
|
109
|
+
fontMono: 'monospace',
|
|
110
|
+
fontDisplay: 'Georgia, serif',
|
|
111
|
+
containerMax: '1200px',
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
hero: {
|
|
115
|
+
tagline: 'Our Blog',
|
|
116
|
+
titleLine1: 'Latest',
|
|
117
|
+
titleLine2: 'Articles',
|
|
118
|
+
description: 'Welcome to our blog.',
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
ui: {
|
|
122
|
+
readMoreLabel: 'Read more β',
|
|
123
|
+
btnPrev: 'Previous',
|
|
124
|
+
btnNext: 'Next',
|
|
125
|
+
commentButtonColor: 'var(--bk-accent)',
|
|
126
|
+
commentButtonTextColor: 'var(--bk-black)',
|
|
127
|
+
paginationStyle: 'minimal', // 'minimal' | 'numbered'
|
|
128
|
+
// paginationBtnBg: '#facc15',
|
|
129
|
+
// paginationBtnText: '#0a0a0a',
|
|
130
|
+
// paginationBtnHoverBg: '#0a0a0a',
|
|
131
|
+
// paginationBtnHoverText: '#ffffff',
|
|
132
|
+
// paginationActiveBg: '#facc15',
|
|
133
|
+
// paginationActiveText: '#0a0a0a',
|
|
109
134
|
},
|
|
110
135
|
});
|
|
111
136
|
```
|
|
112
137
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
|
118
|
-
|
|
|
119
|
-
| `
|
|
120
|
-
| `
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
124
|
-
| `
|
|
125
|
-
| `
|
|
126
|
-
| `
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
### theme
|
|
141
|
+
|
|
142
|
+
| Property | Default | Description |
|
|
143
|
+
| :------------- | :---------------------- | :---------------------------------- |
|
|
144
|
+
| `accent` | `#facc15` | Primary accent color |
|
|
145
|
+
| `background` | `#ffffff` | Blog section background |
|
|
146
|
+
| `surface` | `#f8f8f8` | Cards and sidebar background |
|
|
147
|
+
| `text` | `#0a0a0a` | Primary text color |
|
|
148
|
+
| `muted` | `#6b7280` | Secondary text color |
|
|
149
|
+
| `mutedLight` | `#9ca3af` | Subtle text color |
|
|
150
|
+
| `border` | `#e5e7eb` | Border color |
|
|
151
|
+
| `black` | `#0a0a0a` | Badge and title highlight |
|
|
152
|
+
| `white` | `#ffffff` | Text on dark backgrounds |
|
|
153
|
+
| `fontHeading` | `Georgia, serif` | Heading font |
|
|
154
|
+
| `fontBody` | `system-ui, sans-serif` | Body font |
|
|
155
|
+
| `fontMono` | `monospace` | Monospace font |
|
|
156
|
+
| `fontDisplay` | `Georgia, serif` | Display/hero font |
|
|
157
|
+
| `containerMax` | `1200px` | Max width of the blog container |
|
|
127
158
|
|
|
128
159
|
---
|
|
129
160
|
|
|
130
|
-
|
|
161
|
+
### hero
|
|
162
|
+
|
|
163
|
+
| Property | Default | Description |
|
|
164
|
+
| :------------ | :--------------------- | :------------------------------ |
|
|
165
|
+
| `tagline` | `Our Blog` | Badge text above the title |
|
|
166
|
+
| `titleLine1` | `Latest` | First line of the hero title |
|
|
167
|
+
| `titleLine2` | `Articles` | Second line (highlighted) |
|
|
168
|
+
| `description` | `Welcome to our blog.` | Paragraph below the title |
|
|
131
169
|
|
|
132
|
-
|
|
133
|
-
Featured post on the left + smaller posts on the right.
|
|
170
|
+
---
|
|
134
171
|
|
|
135
|
-
###
|
|
136
|
-
|
|
172
|
+
### ui
|
|
173
|
+
|
|
174
|
+
| Property | Default | Description |
|
|
175
|
+
| :----------------------- | :----------------- | :--------------------------------- |
|
|
176
|
+
| `readMoreLabel` | `Read more β` | Read more button label |
|
|
177
|
+
| `btnPrev` | `Previous` | Previous page button label |
|
|
178
|
+
| `btnNext` | `Next` | Next page button label |
|
|
179
|
+
| `commentButtonColor` | `var(--bk-accent)` | Comment submit button background |
|
|
180
|
+
| `commentButtonTextColor` | `var(--bk-black)` | Comment submit button text color |
|
|
181
|
+
| `paginationStyle` | `minimal` | `minimal` or `numbered` |
|
|
182
|
+
| `paginationBtnBg` | `accent` | PREV/NEXT button background |
|
|
183
|
+
| `paginationBtnText` | `black` | PREV/NEXT button text color |
|
|
184
|
+
| `paginationBtnHoverBg` | `text` | PREV/NEXT button hover background |
|
|
185
|
+
| `paginationBtnHoverText` | `white` | PREV/NEXT button hover text color |
|
|
186
|
+
| `paginationActiveBg` | `accent` | Active page number background |
|
|
187
|
+
| `paginationActiveText` | `black` | Active page number text color |
|
|
137
188
|
|
|
138
|
-
|
|
139
|
-
Horizontal rows with image on the left.
|
|
189
|
+
---
|
|
140
190
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
191
|
+
## CSS Variables
|
|
192
|
+
|
|
193
|
+
All theme values are available globally with the `--bk-` prefix:
|
|
194
|
+
|
|
195
|
+
```css
|
|
196
|
+
var(--bk-accent)
|
|
197
|
+
var(--bk-background)
|
|
198
|
+
var(--bk-surface)
|
|
199
|
+
var(--bk-text)
|
|
200
|
+
var(--bk-muted)
|
|
201
|
+
var(--bk-muted-light)
|
|
202
|
+
var(--bk-border)
|
|
203
|
+
var(--bk-black)
|
|
204
|
+
var(--bk-white)
|
|
205
|
+
var(--bk-font-heading)
|
|
206
|
+
var(--bk-font-body)
|
|
207
|
+
var(--bk-font-mono)
|
|
208
|
+
var(--bk-font-display)
|
|
209
|
+
var(--bk-container-max)
|
|
210
|
+
var(--bk-pagination-btn-bg)
|
|
211
|
+
var(--bk-pagination-btn-text)
|
|
212
|
+
var(--bk-pagination-btn-hover-bg)
|
|
213
|
+
var(--bk-pagination-btn-hover-text)
|
|
214
|
+
var(--bk-pagination-active-bg)
|
|
215
|
+
var(--bk-pagination-active-text)
|
|
216
|
+
var(--bk-comment-btn-bg)
|
|
217
|
+
var(--bk-comment-btn-text)
|
|
145
218
|
```
|
|
146
219
|
|
|
147
220
|
---
|
|
148
221
|
|
|
222
|
+
## Layouts
|
|
223
|
+
|
|
224
|
+
| Layout | Description |
|
|
225
|
+
| :---------- | :------------------------------------ |
|
|
226
|
+
| `magazine` | Featured post + side grid |
|
|
227
|
+
| `grid` | 3-column card grid |
|
|
228
|
+
| `featured` | Large hero image + grid below |
|
|
229
|
+
| `cards` | Image background with text overlay |
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
149
233
|
## Components
|
|
150
234
|
|
|
151
235
|
### `<BlogList>`
|
|
152
236
|
|
|
153
237
|
```astro
|
|
154
238
|
---
|
|
155
|
-
import { BlogList } from
|
|
239
|
+
import { BlogList } from 'astro-blog-kit/components';
|
|
156
240
|
---
|
|
157
241
|
<BlogList
|
|
158
242
|
posts={posts}
|
|
@@ -161,7 +245,7 @@ import { BlogList } from "astro-blog-kit/components";
|
|
|
161
245
|
basePath="/blog/page/"
|
|
162
246
|
blogBase="/blog/"
|
|
163
247
|
dateLocale="en-US"
|
|
164
|
-
t={
|
|
248
|
+
t={bt}
|
|
165
249
|
locale="en"
|
|
166
250
|
layout="magazine"
|
|
167
251
|
/>
|
|
@@ -171,7 +255,7 @@ import { BlogList } from "astro-blog-kit/components";
|
|
|
171
255
|
|
|
172
256
|
```astro
|
|
173
257
|
---
|
|
174
|
-
import { BlogPost } from
|
|
258
|
+
import { BlogPost } from 'astro-blog-kit/components';
|
|
175
259
|
---
|
|
176
260
|
<BlogPost post={post} t={t} lang="en" />
|
|
177
261
|
```
|
|
@@ -180,7 +264,7 @@ import { BlogPost } from "astro-blog-kit/components";
|
|
|
180
264
|
|
|
181
265
|
```astro
|
|
182
266
|
---
|
|
183
|
-
import { Comments } from
|
|
267
|
+
import { Comments } from 'astro-blog-kit/components';
|
|
184
268
|
---
|
|
185
269
|
<Comments comments={comments} postId={post.id ?? 0} />
|
|
186
270
|
```
|
|
@@ -189,7 +273,7 @@ import { Comments } from "astro-blog-kit/components";
|
|
|
189
273
|
|
|
190
274
|
```astro
|
|
191
275
|
---
|
|
192
|
-
import { CommentForm } from
|
|
276
|
+
import { CommentForm } from 'astro-blog-kit/components';
|
|
193
277
|
---
|
|
194
278
|
<CommentForm postId={post.id ?? 0} apiRoute="/api/comments" />
|
|
195
279
|
```
|
|
@@ -201,30 +285,21 @@ import { CommentForm } from "astro-blog-kit/components";
|
|
|
201
285
|
### WordPress client
|
|
202
286
|
|
|
203
287
|
```ts
|
|
204
|
-
import { createWPClient } from
|
|
288
|
+
import { createWPClient } from 'astro-blog-kit/utils';
|
|
205
289
|
|
|
206
|
-
const wp = createWPClient(
|
|
290
|
+
const wp = createWPClient('https://cms.yourdomain.com');
|
|
207
291
|
|
|
208
|
-
// Get paginated posts
|
|
209
292
|
const { posts, total, totalPages } = await wp.getPosts({ perPage: 5, page: 1 });
|
|
210
|
-
|
|
211
|
-
// Get all posts (for getStaticPaths)
|
|
212
293
|
const posts = await wp.getAllPosts();
|
|
213
|
-
|
|
214
|
-
// Get single post by slug
|
|
215
|
-
const post = await wp.getPost("my-post-slug");
|
|
216
|
-
|
|
217
|
-
// Get comments for a post
|
|
294
|
+
const post = await wp.getPost('my-post-slug');
|
|
218
295
|
const comments = await wp.getComments(postId);
|
|
219
|
-
|
|
220
|
-
// Get categories
|
|
221
296
|
const categories = await wp.getCategories();
|
|
222
297
|
```
|
|
223
298
|
|
|
224
299
|
### i18n helpers
|
|
225
300
|
|
|
226
301
|
```ts
|
|
227
|
-
import { getLang, useTranslations, getBlogBase } from
|
|
302
|
+
import { getLang, useTranslations, getBlogBase } from 'astro-blog-kit/utils';
|
|
228
303
|
|
|
229
304
|
const lang = getLang(Astro.url, import.meta.env.BASE_URL, config);
|
|
230
305
|
const t = useTranslations(lang, { en, es });
|
|
@@ -234,12 +309,9 @@ const blogBase = getBlogBase(lang, import.meta.env.BASE_URL, config);
|
|
|
234
309
|
### Static paths helpers
|
|
235
310
|
|
|
236
311
|
```ts
|
|
237
|
-
import { getStaticPathsForPosts, getStaticPathsForPages } from
|
|
312
|
+
import { getStaticPathsForPosts, getStaticPathsForPages } from 'astro-blog-kit/utils';
|
|
238
313
|
|
|
239
|
-
// For [...slug].astro
|
|
240
314
|
export const getStaticPaths = () => getStaticPathsForPosts(posts);
|
|
241
|
-
|
|
242
|
-
// For [page].astro
|
|
243
315
|
export const getStaticPaths = () => getStaticPathsForPages(posts, { postsPerPage: 5 });
|
|
244
316
|
```
|
|
245
317
|
|
|
@@ -251,19 +323,12 @@ Copy `node_modules/astro-blog-kit/examples/deploy-ftp.yml` to `.github/workflows
|
|
|
251
323
|
|
|
252
324
|
Add these secrets to your GitHub repository (**Settings β Secrets**):
|
|
253
325
|
|
|
254
|
-
| Secret
|
|
255
|
-
|
|
256
|
-
| `FTP_HOST`
|
|
257
|
-
| `FTP_USERNAME
|
|
258
|
-
| `FTP_PASSWORD
|
|
259
|
-
| `WP_API_URL`
|
|
260
|
-
|
|
261
|
-
The workflow triggers on:
|
|
262
|
-
- Push to `main`
|
|
263
|
-
- WordPress webhook (`wp_update`, `wp_comment`)
|
|
264
|
-
- Manual trigger
|
|
265
|
-
|
|
266
|
-
To trigger from WordPress, install the **WP Webhooks** plugin and configure it to send a `repository_dispatch` event to GitHub when a post is published or a comment is approved.
|
|
326
|
+
| Secret | Description |
|
|
327
|
+
| :------------ | :-------------------- |
|
|
328
|
+
| `FTP_HOST` | Your server hostname |
|
|
329
|
+
| `FTP_USERNAME`| FTP username |
|
|
330
|
+
| `FTP_PASSWORD`| FTP password |
|
|
331
|
+
| `WP_API_URL` | Your WordPress URL |
|
|
267
332
|
|
|
268
333
|
---
|
|
269
334
|
|
|
@@ -273,8 +338,8 @@ To trigger from WordPress, install the **WP Webhooks** plugin and configure it t
|
|
|
273
338
|
// astro.config.mjs
|
|
274
339
|
blogKit({
|
|
275
340
|
i18n: {
|
|
276
|
-
locales: [
|
|
277
|
-
defaultLocale:
|
|
341
|
+
locales: ['en', 'es'],
|
|
342
|
+
defaultLocale: 'en',
|
|
278
343
|
},
|
|
279
344
|
})
|
|
280
345
|
```
|
|
@@ -287,7 +352,7 @@ With i18n enabled:
|
|
|
287
352
|
|
|
288
353
|
## Requirements
|
|
289
354
|
|
|
290
|
-
- Astro v4 or
|
|
355
|
+
- Astro v4, v5, v6, or v7
|
|
291
356
|
- Node.js 18+
|
|
292
357
|
- WordPress with REST API enabled
|
|
293
358
|
|
package/define-config.ts
CHANGED
|
@@ -2,7 +2,16 @@
|
|
|
2
2
|
// astro-blog-kit Β· define-config.ts
|
|
3
3
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
BlogKitConfig,
|
|
7
|
+
BlogTheme,
|
|
8
|
+
BlogHero,
|
|
9
|
+
BlogHeroLocale,
|
|
10
|
+
BlogUI,
|
|
11
|
+
BlogUILocale,
|
|
12
|
+
} from "./types";
|
|
13
|
+
|
|
14
|
+
// ββ Interfaces pΓΊblicas βββββββββββββββββββββββββββββββββββββββ
|
|
6
15
|
|
|
7
16
|
export interface BlogConfig {
|
|
8
17
|
/** URL de tu WordPress. Ej: https://cms.tudominio.com */
|
|
@@ -26,132 +35,170 @@ export interface BlogConfig {
|
|
|
26
35
|
};
|
|
27
36
|
}
|
|
28
37
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
*
|
|
32
|
-
* @example
|
|
33
|
-
* ```ts
|
|
34
|
-
* // blog.config.ts
|
|
35
|
-
* import { defineBlogConfig } from 'astro-blog-kit';
|
|
36
|
-
*
|
|
37
|
-
* export default defineBlogConfig({
|
|
38
|
-
* wpUrl: 'https://cms.tudominio.com',
|
|
39
|
-
* postsPerPage: 5,
|
|
40
|
-
* defaultLayout: 'featured',
|
|
41
|
-
* locale: 'en',
|
|
42
|
-
* theme: {
|
|
43
|
-
* accent: '#facc15',
|
|
44
|
-
* background: '#0a1a0a',
|
|
45
|
-
* text: '#ffffff',
|
|
46
|
-
* },
|
|
47
|
-
* hero: {
|
|
48
|
-
* tagline: 'Technical Resources',
|
|
49
|
-
* titleLine1: 'Building',
|
|
50
|
-
* titleLine2: 'Insights',
|
|
51
|
-
* description: 'Practical knowledge for architects and engineers.',
|
|
52
|
-
* },
|
|
53
|
-
* ui: {
|
|
54
|
-
* readMoreLabel: 'Read more β',
|
|
55
|
-
* btnPrev: 'Previous',
|
|
56
|
-
* btnNext: 'Next',
|
|
57
|
-
* commentButtonColor: '#facc15',
|
|
58
|
-
* commentButtonTextColor: '#0a0a0a',
|
|
59
|
-
* paginationStyle: 'minimal',
|
|
60
|
-
* },
|
|
61
|
-
* });
|
|
62
|
-
* ```
|
|
63
|
-
*/
|
|
38
|
+
// ββ defineBlogConfig ββββββββββββββββββββββββββββββββββββββββββ
|
|
39
|
+
|
|
64
40
|
export function defineBlogConfig(config: BlogConfig): BlogConfig {
|
|
65
41
|
return {
|
|
66
|
-
postsPerPage:
|
|
42
|
+
postsPerPage: 5,
|
|
67
43
|
defaultLayout: "magazine",
|
|
68
|
-
locale:
|
|
44
|
+
locale: "en",
|
|
69
45
|
...config,
|
|
70
46
|
};
|
|
71
47
|
}
|
|
72
48
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
*/
|
|
49
|
+
// ββ toBlogKitConfig βββββββββββββββββββββββββββββββββββββββββββ
|
|
50
|
+
|
|
76
51
|
export function toBlogKitConfig(config: BlogConfig): BlogKitConfig {
|
|
77
52
|
return {
|
|
78
|
-
postsPerPage:
|
|
53
|
+
postsPerPage: config.postsPerPage,
|
|
79
54
|
defaultLayout: config.defaultLayout,
|
|
80
|
-
theme:
|
|
81
|
-
hero:
|
|
82
|
-
ui:
|
|
83
|
-
i18n:
|
|
55
|
+
theme: config.theme,
|
|
56
|
+
hero: config.hero,
|
|
57
|
+
ui: config.ui,
|
|
58
|
+
i18n: config.i18n,
|
|
84
59
|
};
|
|
85
60
|
}
|
|
86
61
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
62
|
+
// ββ Helpers de detecciΓ³n de formato ββββββββββββββββββββββββββ
|
|
63
|
+
|
|
64
|
+
function isHeroI18n(hero: BlogHero): hero is Record<string, BlogHeroLocale> {
|
|
65
|
+
return typeof hero === "object" &&
|
|
66
|
+
Object.values(hero).some((v) => typeof v === "object" && v !== null);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function isUIi18n(ui: BlogUI): ui is Record<string, BlogUILocale> {
|
|
70
|
+
return typeof ui === "object" &&
|
|
71
|
+
Object.values(ui).some((v) => typeof v === "object" && v !== null);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ββ Defaults internos βββββββββββββββββββββββββββββββββββββββββ
|
|
75
|
+
|
|
76
|
+
const HERO_DEFAULTS: Record<string, Required<BlogHeroLocale>> = {
|
|
77
|
+
en: {
|
|
78
|
+
tagline: "Our Blog",
|
|
79
|
+
titleLine1: "Latest",
|
|
80
|
+
titleLine2: "Articles",
|
|
81
|
+
description: "Welcome to our blog.",
|
|
82
|
+
},
|
|
83
|
+
es: {
|
|
84
|
+
tagline: "Nuestro Blog",
|
|
85
|
+
titleLine1: "Γltimos",
|
|
86
|
+
titleLine2: "ArtΓculos",
|
|
87
|
+
description: "Bienvenido a nuestro blog.",
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const UI_DEFAULTS: Record<string, Required<BlogUILocale>> = {
|
|
92
|
+
en: {
|
|
93
|
+
readMoreLabel: "Read more β",
|
|
94
|
+
btnPrev: "Previous",
|
|
95
|
+
btnNext: "Next",
|
|
96
|
+
commentButtonColor: "var(--bk-accent)",
|
|
97
|
+
commentButtonTextColor: "var(--bk-black)",
|
|
98
|
+
paginationStyle: "minimal",
|
|
99
|
+
paginationBtnBg: "var(--bk-accent)",
|
|
100
|
+
paginationBtnText: "var(--bk-black)",
|
|
101
|
+
paginationBtnHoverBg: "var(--bk-text)",
|
|
102
|
+
paginationBtnHoverText: "var(--bk-white)",
|
|
103
|
+
paginationActiveBg: "var(--bk-accent)",
|
|
104
|
+
paginationActiveText: "var(--bk-black)",
|
|
105
|
+
},
|
|
106
|
+
es: {
|
|
107
|
+
readMoreLabel: "Leer mΓ‘s β",
|
|
108
|
+
btnPrev: "Anterior",
|
|
109
|
+
btnNext: "Siguiente",
|
|
110
|
+
commentButtonColor: "var(--bk-accent)",
|
|
111
|
+
commentButtonTextColor: "var(--bk-black)",
|
|
112
|
+
paginationStyle: "minimal",
|
|
113
|
+
paginationBtnBg: "var(--bk-accent)",
|
|
114
|
+
paginationBtnText: "var(--bk-black)",
|
|
115
|
+
paginationBtnHoverBg: "var(--bk-text)",
|
|
116
|
+
paginationBtnHoverText: "var(--bk-white)",
|
|
117
|
+
paginationActiveBg: "var(--bk-accent)",
|
|
118
|
+
paginationActiveText: "var(--bk-black)",
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// ββ resolveHero βββββββββββββββββββββββββββββββββββββββββββββββ
|
|
123
|
+
|
|
91
124
|
export function resolveHero(
|
|
92
125
|
hero: BlogHero | undefined,
|
|
93
126
|
locale: string
|
|
94
|
-
): Required<
|
|
95
|
-
const
|
|
96
|
-
en: {
|
|
97
|
-
tagline: "Our Blog",
|
|
98
|
-
titleLine1: "Latest",
|
|
99
|
-
titleLine2: "Articles",
|
|
100
|
-
description: "Welcome to our blog.",
|
|
101
|
-
},
|
|
102
|
-
es: {
|
|
103
|
-
tagline: "Nuestro Blog",
|
|
104
|
-
titleLine1: "Γltimos",
|
|
105
|
-
titleLine2: "ArtΓculos",
|
|
106
|
-
description: "Bienvenido a nuestro blog.",
|
|
107
|
-
},
|
|
108
|
-
};
|
|
127
|
+
): Required<BlogHeroLocale> {
|
|
128
|
+
const d = HERO_DEFAULTS[locale] ?? HERO_DEFAULTS["en"];
|
|
109
129
|
|
|
110
|
-
|
|
130
|
+
if (!hero) return d;
|
|
111
131
|
|
|
132
|
+
if (isHeroI18n(hero)) {
|
|
133
|
+
// Formato i18n: busca locale exacto β fallback 'en' β defaults internos
|
|
134
|
+
const src = hero[locale] ?? hero["en"] ?? {};
|
|
135
|
+
return {
|
|
136
|
+
tagline: src.tagline ?? d.tagline,
|
|
137
|
+
titleLine1: src.titleLine1 ?? d.titleLine1,
|
|
138
|
+
titleLine2: src.titleLine2 ?? d.titleLine2,
|
|
139
|
+
description: src.description ?? d.description,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Formato plano legacy β backward compatible
|
|
144
|
+
const flat = hero as BlogHeroLocale;
|
|
112
145
|
return {
|
|
113
|
-
tagline:
|
|
114
|
-
titleLine1:
|
|
115
|
-
titleLine2:
|
|
116
|
-
description:
|
|
146
|
+
tagline: flat.tagline ?? d.tagline,
|
|
147
|
+
titleLine1: flat.titleLine1 ?? d.titleLine1,
|
|
148
|
+
titleLine2: flat.titleLine2 ?? d.titleLine2,
|
|
149
|
+
description: flat.description ?? d.description,
|
|
117
150
|
};
|
|
118
151
|
}
|
|
119
152
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
* Usado internamente por BlogList.astro y Pagination.astro
|
|
123
|
-
*/
|
|
153
|
+
// ββ resolveUI βββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
154
|
+
|
|
124
155
|
export function resolveUI(
|
|
125
156
|
ui: BlogUI | undefined,
|
|
126
157
|
locale: string
|
|
127
|
-
): Required<
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
btnNext: "Siguiente",
|
|
141
|
-
commentButtonColor: "var(--bk-accent)",
|
|
142
|
-
commentButtonTextColor: "var(--bk-black)",
|
|
143
|
-
paginationStyle: "minimal",
|
|
144
|
-
},
|
|
145
|
-
};
|
|
158
|
+
): Required<BlogUILocale> {
|
|
159
|
+
const d = UI_DEFAULTS[locale] ?? UI_DEFAULTS["en"];
|
|
160
|
+
|
|
161
|
+
if (!ui) return d;
|
|
162
|
+
|
|
163
|
+
if (isUIi18n(ui)) {
|
|
164
|
+
// Campos visuales (colores) viven en cualquier locale; los buscamos
|
|
165
|
+
// en todos los locales disponibles para usarlos como fallback compartido.
|
|
166
|
+
const allLocales = Object.values(ui as Record<string, BlogUILocale>);
|
|
167
|
+
const visual = allLocales.find((v) => v.paginationBtnBg) ?? {};
|
|
168
|
+
|
|
169
|
+
const src = (ui as Record<string, BlogUILocale>)[locale] ??
|
|
170
|
+
(ui as Record<string, BlogUILocale>)["en"] ?? {};
|
|
146
171
|
|
|
147
|
-
|
|
172
|
+
return {
|
|
173
|
+
readMoreLabel: src.readMoreLabel ?? d.readMoreLabel,
|
|
174
|
+
btnPrev: src.btnPrev ?? d.btnPrev,
|
|
175
|
+
btnNext: src.btnNext ?? d.btnNext,
|
|
176
|
+
commentButtonColor: src.commentButtonColor ?? visual.commentButtonColor ?? d.commentButtonColor,
|
|
177
|
+
commentButtonTextColor: src.commentButtonTextColor ?? visual.commentButtonTextColor ?? d.commentButtonTextColor,
|
|
178
|
+
paginationStyle: src.paginationStyle ?? visual.paginationStyle ?? d.paginationStyle,
|
|
179
|
+
paginationBtnBg: src.paginationBtnBg ?? visual.paginationBtnBg ?? d.paginationBtnBg,
|
|
180
|
+
paginationBtnText: src.paginationBtnText ?? visual.paginationBtnText ?? d.paginationBtnText,
|
|
181
|
+
paginationBtnHoverBg: src.paginationBtnHoverBg ?? visual.paginationBtnHoverBg ?? d.paginationBtnHoverBg,
|
|
182
|
+
paginationBtnHoverText: src.paginationBtnHoverText ?? visual.paginationBtnHoverText ?? d.paginationBtnHoverText,
|
|
183
|
+
paginationActiveBg: src.paginationActiveBg ?? visual.paginationActiveBg ?? d.paginationActiveBg,
|
|
184
|
+
paginationActiveText: src.paginationActiveText ?? visual.paginationActiveText ?? d.paginationActiveText,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
148
187
|
|
|
188
|
+
// Formato plano legacy β backward compatible
|
|
189
|
+
const flat = ui as BlogUILocale;
|
|
149
190
|
return {
|
|
150
|
-
readMoreLabel:
|
|
151
|
-
btnPrev:
|
|
152
|
-
btnNext:
|
|
153
|
-
commentButtonColor:
|
|
154
|
-
commentButtonTextColor:
|
|
155
|
-
paginationStyle:
|
|
191
|
+
readMoreLabel: flat.readMoreLabel ?? d.readMoreLabel,
|
|
192
|
+
btnPrev: flat.btnPrev ?? d.btnPrev,
|
|
193
|
+
btnNext: flat.btnNext ?? d.btnNext,
|
|
194
|
+
commentButtonColor: flat.commentButtonColor ?? d.commentButtonColor,
|
|
195
|
+
commentButtonTextColor: flat.commentButtonTextColor ?? d.commentButtonTextColor,
|
|
196
|
+
paginationStyle: flat.paginationStyle ?? d.paginationStyle,
|
|
197
|
+
paginationBtnBg: flat.paginationBtnBg ?? d.paginationBtnBg,
|
|
198
|
+
paginationBtnText: flat.paginationBtnText ?? d.paginationBtnText,
|
|
199
|
+
paginationBtnHoverBg: flat.paginationBtnHoverBg ?? d.paginationBtnHoverBg,
|
|
200
|
+
paginationBtnHoverText: flat.paginationBtnHoverText ?? d.paginationBtnHoverText,
|
|
201
|
+
paginationActiveBg: flat.paginationActiveBg ?? d.paginationActiveBg,
|
|
202
|
+
paginationActiveText: flat.paginationActiveText ?? d.paginationActiveText,
|
|
156
203
|
};
|
|
157
204
|
}
|
package/package.json
CHANGED
|
@@ -2,9 +2,9 @@ import { defineBlogConfig } from 'astro-blog-kit';
|
|
|
2
2
|
|
|
3
3
|
export default defineBlogConfig({
|
|
4
4
|
wpUrl: import.meta.env.WP_API_URL || '__WP_URL__',
|
|
5
|
-
postsPerPage:
|
|
5
|
+
postsPerPage: __POSTS_PER_PAGE__,
|
|
6
6
|
defaultLayout: '__DEFAULT_LAYOUT__',
|
|
7
|
-
locale:
|
|
7
|
+
locale: '__LOCALE__',
|
|
8
8
|
|
|
9
9
|
theme: {
|
|
10
10
|
accent: '#facc15',
|
|
@@ -23,28 +23,49 @@ export default defineBlogConfig({
|
|
|
23
23
|
containerMax: '1200px',
|
|
24
24
|
},
|
|
25
25
|
|
|
26
|
+
// ββ Hero ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
27
|
+
// Sitio i18n: un objeto por locale.
|
|
28
|
+
// Sitio monolingΓΌe: puedes usar el formato plano:
|
|
29
|
+
// hero: { tagline: 'Our Blog', titleLine1: 'Latest', ... }
|
|
26
30
|
hero: {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
en: {
|
|
32
|
+
tagline: 'Our Blog',
|
|
33
|
+
titleLine1: 'Latest',
|
|
34
|
+
titleLine2: 'Articles',
|
|
35
|
+
description: 'Welcome to our blog.',
|
|
36
|
+
},
|
|
37
|
+
es: {
|
|
38
|
+
tagline: 'Nuestro Blog',
|
|
39
|
+
titleLine1: 'Γltimos',
|
|
40
|
+
titleLine2: 'ArtΓculos',
|
|
41
|
+
description: 'Bienvenido a nuestro blog.',
|
|
42
|
+
},
|
|
31
43
|
},
|
|
32
44
|
|
|
45
|
+
// ββ UI labels ββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
46
|
+
// Los labels de texto van por locale.
|
|
47
|
+
// Los campos visuales (colores, paginationStyle) son compartidos:
|
|
48
|
+
// ponlos en cualquier locale y aplican a todos.
|
|
33
49
|
ui: {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
en: {
|
|
51
|
+
readMoreLabel: 'Read more β',
|
|
52
|
+
btnPrev: 'Previous',
|
|
53
|
+
btnNext: 'Next',
|
|
54
|
+
// ββ Colores compartidos (van aquΓ una sola vez) ββββββββββ
|
|
55
|
+
commentButtonColor: 'var(--bk-accent)',
|
|
56
|
+
commentButtonTextColor: 'var(--bk-black)',
|
|
57
|
+
paginationStyle: 'minimal',
|
|
58
|
+
// paginationBtnBg: '#facc15',
|
|
59
|
+
// paginationBtnText: '#0a0a0a',
|
|
60
|
+
// paginationBtnHoverBg: '#0a0a0a',
|
|
61
|
+
// paginationBtnHoverText: '#ffffff',
|
|
62
|
+
// paginationActiveBg: '#facc15',
|
|
63
|
+
// paginationActiveText: '#0a0a0a',
|
|
64
|
+
},
|
|
65
|
+
es: {
|
|
66
|
+
readMoreLabel: 'Leer mΓ‘s β',
|
|
67
|
+
btnPrev: 'Anterior',
|
|
68
|
+
btnNext: 'Siguiente',
|
|
69
|
+
},
|
|
49
70
|
},
|
|
50
|
-
});
|
|
71
|
+
});
|
package/types.ts
CHANGED
|
@@ -29,109 +29,144 @@ export interface I18nConfig {
|
|
|
29
29
|
|
|
30
30
|
export interface BlogTranslations {
|
|
31
31
|
blog: {
|
|
32
|
-
tagline:
|
|
32
|
+
tagline: string;
|
|
33
33
|
title_line1: string;
|
|
34
34
|
title_line2: string;
|
|
35
35
|
description: string;
|
|
36
|
-
btncta:
|
|
37
|
-
btn_prev:
|
|
38
|
-
btn_next:
|
|
36
|
+
btncta: string;
|
|
37
|
+
btn_prev: string;
|
|
38
|
+
btn_next: string;
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export interface PaginationProps {
|
|
43
43
|
currentPage: number;
|
|
44
|
-
totalPages:
|
|
45
|
-
basePath:
|
|
46
|
-
blogBase:
|
|
47
|
-
t:
|
|
44
|
+
totalPages: number;
|
|
45
|
+
basePath: string;
|
|
46
|
+
blogBase: string;
|
|
47
|
+
t: BlogTranslations;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
export interface BlogListProps {
|
|
51
|
-
posts:
|
|
51
|
+
posts: BlogPost[];
|
|
52
52
|
currentPage: number;
|
|
53
|
-
totalPages:
|
|
54
|
-
basePath:
|
|
55
|
-
blogBase:
|
|
56
|
-
dateLocale:
|
|
57
|
-
t:
|
|
58
|
-
locale:
|
|
59
|
-
layout?:
|
|
53
|
+
totalPages: number;
|
|
54
|
+
basePath: string;
|
|
55
|
+
blogBase: string;
|
|
56
|
+
dateLocale: string;
|
|
57
|
+
t: BlogTranslations;
|
|
58
|
+
locale: string;
|
|
59
|
+
layout?: BlogListLayout;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
export interface BlogPostProps {
|
|
63
63
|
post: BlogPost;
|
|
64
|
-
t:
|
|
64
|
+
t: BlogTranslations;
|
|
65
65
|
lang: string;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
// ββ Theme βββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
69
|
+
|
|
68
70
|
export interface BlogTheme {
|
|
69
|
-
accent?:
|
|
70
|
-
background?:
|
|
71
|
-
surface?:
|
|
72
|
-
text?:
|
|
73
|
-
muted?:
|
|
74
|
-
mutedLight?:
|
|
75
|
-
border?:
|
|
76
|
-
black?:
|
|
77
|
-
white?:
|
|
78
|
-
fontHeading?:
|
|
79
|
-
fontBody?:
|
|
80
|
-
fontMono?:
|
|
81
|
-
fontDisplay?:
|
|
71
|
+
accent?: string;
|
|
72
|
+
background?: string;
|
|
73
|
+
surface?: string;
|
|
74
|
+
text?: string;
|
|
75
|
+
muted?: string;
|
|
76
|
+
mutedLight?: string;
|
|
77
|
+
border?: string;
|
|
78
|
+
black?: string;
|
|
79
|
+
white?: string;
|
|
80
|
+
fontHeading?: string;
|
|
81
|
+
fontBody?: string;
|
|
82
|
+
fontMono?: string;
|
|
83
|
+
fontDisplay?: string;
|
|
82
84
|
containerMax?: string;
|
|
83
85
|
}
|
|
84
86
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
// ββ Hero ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
88
|
+
|
|
89
|
+
/** Textos del hero para un ΓΊnico locale */
|
|
90
|
+
export interface BlogHeroLocale {
|
|
91
|
+
tagline?: string;
|
|
92
|
+
titleLine1?: string;
|
|
93
|
+
titleLine2?: string;
|
|
89
94
|
description?: string;
|
|
90
95
|
}
|
|
91
96
|
|
|
92
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Acepta dos formatos:
|
|
99
|
+
* - Plano (sitio monolingΓΌe): { tagline: 'Our Blog', ... }
|
|
100
|
+
* - Por locale (sitio i18n): { en: { tagline: 'Our Blog' }, es: { tagline: 'Nuestro Blog' } }
|
|
101
|
+
*/
|
|
102
|
+
export type BlogHero = BlogHeroLocale | Record<string, BlogHeroLocale>;
|
|
103
|
+
|
|
104
|
+
// ββ UI ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
105
|
+
|
|
106
|
+
/** Labels y colores de UI para un ΓΊnico locale */
|
|
107
|
+
export interface BlogUILocale {
|
|
93
108
|
/** Texto del botΓ³n "leer mΓ‘s". @default "Read more β" */
|
|
94
|
-
readMoreLabel?:
|
|
109
|
+
readMoreLabel?: string;
|
|
95
110
|
/** Texto del botΓ³n de pΓ‘gina anterior. @default "Previous" */
|
|
96
|
-
btnPrev?:
|
|
111
|
+
btnPrev?: string;
|
|
97
112
|
/** Texto del botΓ³n de pΓ‘gina siguiente. @default "Next" */
|
|
98
|
-
btnNext?:
|
|
113
|
+
btnNext?: string;
|
|
99
114
|
/** Color de fondo del botΓ³n de comentarios. @default var(--bk-accent) */
|
|
100
|
-
commentButtonColor?:
|
|
115
|
+
commentButtonColor?: string;
|
|
101
116
|
/** Color del texto del botΓ³n de comentarios. @default var(--bk-black) */
|
|
102
117
|
commentButtonTextColor?: string;
|
|
103
118
|
/** Estilo de paginaciΓ³n. @default "minimal" */
|
|
104
|
-
paginationStyle?:
|
|
105
|
-
/** Fondo botones PREV/NEXT. @default accent */
|
|
106
|
-
paginationBtnBg?:
|
|
107
|
-
/** Texto botones PREV/NEXT. @default black */
|
|
108
|
-
paginationBtnText?:
|
|
109
|
-
/** Fondo botones PREV/NEXT en hover. @default text */
|
|
110
|
-
paginationBtnHoverBg?:
|
|
111
|
-
/** Texto botones PREV/NEXT en hover. @default white */
|
|
119
|
+
paginationStyle?: "minimal" | "numbered";
|
|
120
|
+
/** Fondo botones PREV/NEXT. @default var(--bk-accent) */
|
|
121
|
+
paginationBtnBg?: string;
|
|
122
|
+
/** Texto botones PREV/NEXT. @default var(--bk-black) */
|
|
123
|
+
paginationBtnText?: string;
|
|
124
|
+
/** Fondo botones PREV/NEXT en hover. @default var(--bk-text) */
|
|
125
|
+
paginationBtnHoverBg?: string;
|
|
126
|
+
/** Texto botones PREV/NEXT en hover. @default var(--bk-white) */
|
|
112
127
|
paginationBtnHoverText?: string;
|
|
113
|
-
/** Fondo pΓ‘gina activa. @default accent */
|
|
114
|
-
paginationActiveBg?:
|
|
115
|
-
/** Texto pΓ‘gina activa. @default black */
|
|
116
|
-
paginationActiveText?:
|
|
128
|
+
/** Fondo pΓ‘gina activa. @default var(--bk-accent) */
|
|
129
|
+
paginationActiveBg?: string;
|
|
130
|
+
/** Texto pΓ‘gina activa. @default var(--bk-black) */
|
|
131
|
+
paginationActiveText?: string;
|
|
117
132
|
}
|
|
118
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Acepta dos formatos:
|
|
136
|
+
* - Plano (sitio monolingΓΌe): { readMoreLabel: 'Read more', ... }
|
|
137
|
+
* - Por locale (sitio i18n): { en: { readMoreLabel: 'Read more' }, es: { readMoreLabel: 'Leer mΓ‘s' } }
|
|
138
|
+
*
|
|
139
|
+
* Nota: los campos visuales (colores, paginationStyle) son compartidos entre locales.
|
|
140
|
+
* Ponlos en cualquier locale (ej. `en`) β el resolver los tomarΓ‘ como fallback global.
|
|
141
|
+
*/
|
|
142
|
+
export type BlogUI = BlogUILocale | Record<string, BlogUILocale>;
|
|
143
|
+
|
|
144
|
+
// ββ Alias para backward compat ββββββββββββββββββββββββββββββββ
|
|
145
|
+
/** @deprecated Usa BlogHeroLocale */
|
|
146
|
+
export type { BlogHeroLocale as BlogHeroFlat };
|
|
147
|
+
/** @deprecated Usa BlogUILocale */
|
|
148
|
+
export type { BlogUILocale as BlogUIFlat };
|
|
149
|
+
|
|
150
|
+
// ββ BlogKitConfig (integration.ts) βββββββββββββββββββββββββββ
|
|
151
|
+
|
|
119
152
|
export interface BlogKitConfig {
|
|
120
|
-
postsPerPage?:
|
|
121
|
-
i18n?:
|
|
122
|
-
defaultLayout?:
|
|
153
|
+
postsPerPage?: number;
|
|
154
|
+
i18n?: I18nConfig;
|
|
155
|
+
defaultLayout?: BlogListLayout;
|
|
123
156
|
collectionName?: string;
|
|
124
|
-
theme?:
|
|
125
|
-
hero?:
|
|
126
|
-
ui?:
|
|
157
|
+
theme?: BlogTheme;
|
|
158
|
+
hero?: BlogHero;
|
|
159
|
+
ui?: BlogUI;
|
|
127
160
|
}
|
|
128
161
|
|
|
162
|
+
// ββ Static paths ββββββββββββββββββββββββββββββββββββββββββββββ
|
|
163
|
+
|
|
129
164
|
export interface PageStaticPath {
|
|
130
165
|
params: { page: string };
|
|
131
|
-
props:
|
|
166
|
+
props: { posts: BlogPost[]; currentPage: number; totalPages: number };
|
|
132
167
|
}
|
|
133
168
|
|
|
134
169
|
export interface PostStaticPath {
|
|
135
170
|
params: { slug: string };
|
|
136
|
-
props:
|
|
171
|
+
props: { post: BlogPost };
|
|
137
172
|
}
|