@weekend-studio/easyblog-next 0.0.48 → 0.0.49
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/dist/app-index.mjs +1 -384
- package/dist/app-index.mjs.map +1 -1
- package/dist/index.mjs +1 -650
- package/dist/index.mjs.map +1 -1
- package/dist/page-index.mjs +1 -441
- package/dist/page-index.mjs.map +1 -1
- package/dist/seo.mjs +1 -70
- package/dist/seo.mjs.map +1 -1
- package/package.json +2 -2
package/dist/app-index.mjs
CHANGED
|
@@ -1,385 +1,2 @@
|
|
|
1
|
-
var
|
|
2
|
-
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
|
-
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
5
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
-
var __spreadValues = (a, b) => {
|
|
7
|
-
for (var prop in b || (b = {}))
|
|
8
|
-
if (__hasOwnProp.call(b, prop))
|
|
9
|
-
__defNormalProp(a, prop, b[prop]);
|
|
10
|
-
if (__getOwnPropSymbols)
|
|
11
|
-
for (var prop of __getOwnPropSymbols(b)) {
|
|
12
|
-
if (__propIsEnum.call(b, prop))
|
|
13
|
-
__defNormalProp(a, prop, b[prop]);
|
|
14
|
-
}
|
|
15
|
-
return a;
|
|
16
|
-
};
|
|
17
|
-
var __objRest = (source, exclude) => {
|
|
18
|
-
var target = {};
|
|
19
|
-
for (var prop in source)
|
|
20
|
-
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
21
|
-
target[prop] = source[prop];
|
|
22
|
-
if (source != null && __getOwnPropSymbols)
|
|
23
|
-
for (var prop of __getOwnPropSymbols(source)) {
|
|
24
|
-
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
25
|
-
target[prop] = source[prop];
|
|
26
|
-
}
|
|
27
|
-
return target;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
// src/NextAppRouterUtils.ts
|
|
31
|
-
import { cache } from "react";
|
|
32
|
-
import { notFound } from "next/navigation";
|
|
33
|
-
|
|
34
|
-
// src/BaseUtils.ts
|
|
35
|
-
async function exchangeToken(config) {
|
|
36
|
-
try {
|
|
37
|
-
const response = await fetch(`${config.apiUrl}/exchange-token`, {
|
|
38
|
-
method: "POST",
|
|
39
|
-
headers: {
|
|
40
|
-
"Authorization": `Bearer ${config.apiKey}`,
|
|
41
|
-
"x-project-id": config.projectId
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
if (!response.ok) {
|
|
45
|
-
console.error("Failed to exchange token:", response);
|
|
46
|
-
throw new Error("Failed to authenticate");
|
|
47
|
-
}
|
|
48
|
-
const data = await response.json();
|
|
49
|
-
return data.token;
|
|
50
|
-
} catch (error) {
|
|
51
|
-
console.error("Failed to exchange token:", error);
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// src/utils.ts
|
|
57
|
-
var getFormattedDate = (date) => {
|
|
58
|
-
if (!date) return "";
|
|
59
|
-
return new Date(date).toISOString().split("T")[0];
|
|
60
|
-
};
|
|
61
|
-
var getVisiblePages = (current, total) => {
|
|
62
|
-
if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1);
|
|
63
|
-
if (current <= 3) return [1, 2, 3, 4, 5, null, total];
|
|
64
|
-
if (current >= total - 2) return [1, null, total - 4, total - 3, total - 2, total - 1, total];
|
|
65
|
-
return [1, null, current - 1, current, current + 1, null, total];
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// src/NextAppRouterUtils.ts
|
|
69
|
-
var getAuthToken = cache(async (config) => {
|
|
70
|
-
return exchangeToken(config);
|
|
71
|
-
});
|
|
72
|
-
async function getBlogPosts(config, params = {}) {
|
|
73
|
-
const token = await getAuthToken(config);
|
|
74
|
-
const queryString = new URLSearchParams(
|
|
75
|
-
Object.entries(params).map(([key, value]) => [key, String(value)])
|
|
76
|
-
).toString();
|
|
77
|
-
const url = `${config.apiUrl}/sdk/blogs${queryString ? `?${queryString}` : ""}`;
|
|
78
|
-
const response = await fetch(url, {
|
|
79
|
-
headers: {
|
|
80
|
-
"Authorization": `Bearer ${token}`,
|
|
81
|
-
"x-project-id": config.projectId
|
|
82
|
-
},
|
|
83
|
-
next: { revalidate: 3600 }
|
|
84
|
-
});
|
|
85
|
-
if (!response.ok) {
|
|
86
|
-
console.error("Failed to fetch blog posts:", response);
|
|
87
|
-
throw new Error(`Failed to fetch blog posts: ${response.status} ${response.statusText}`);
|
|
88
|
-
}
|
|
89
|
-
const data = await response.json();
|
|
90
|
-
return data;
|
|
91
|
-
}
|
|
92
|
-
async function getBlogPost(config, slug) {
|
|
93
|
-
const token = await getAuthToken(config);
|
|
94
|
-
const response = await fetch(`${config.apiUrl}/sdk/blogs/${slug}`, {
|
|
95
|
-
headers: {
|
|
96
|
-
"Authorization": `Bearer ${token}`,
|
|
97
|
-
"x-project-id": config.projectId
|
|
98
|
-
},
|
|
99
|
-
next: { revalidate: 3600 }
|
|
100
|
-
});
|
|
101
|
-
if (!response.ok) {
|
|
102
|
-
throw new Error(`Failed to fetch blog post: ${response.status} ${response.statusText}`);
|
|
103
|
-
}
|
|
104
|
-
return response.json();
|
|
105
|
-
}
|
|
106
|
-
async function getBlogPaths(config) {
|
|
107
|
-
const res = await getBlogPosts(config, { index: 0, limit: 1e4 });
|
|
108
|
-
if (!res.blogs) return [];
|
|
109
|
-
return res.blogs.map((blog) => ({ slug: blog.slug }));
|
|
110
|
-
}
|
|
111
|
-
async function generateMetadata(config, slug) {
|
|
112
|
-
var _a, _b;
|
|
113
|
-
if (slug) {
|
|
114
|
-
const post = await getBlogPost(config, slug);
|
|
115
|
-
if (!post) return notFound();
|
|
116
|
-
return {
|
|
117
|
-
title: post.title,
|
|
118
|
-
description: (_a = post.excerpt) == null ? void 0 : _a.substring(0, 160),
|
|
119
|
-
openGraph: {
|
|
120
|
-
title: post.title,
|
|
121
|
-
description: (_b = post.excerpt) == null ? void 0 : _b.substring(0, 160),
|
|
122
|
-
type: "article",
|
|
123
|
-
publishedTime: getFormattedDate(post.created_at),
|
|
124
|
-
tags: post.tags
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
return {
|
|
129
|
-
title: "Blog",
|
|
130
|
-
description: "Read our latest blog posts",
|
|
131
|
-
openGraph: {
|
|
132
|
-
title: "Blog",
|
|
133
|
-
description: "Read our latest blog posts",
|
|
134
|
-
type: "website"
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// src/NextBlogPage.tsx
|
|
140
|
-
import React from "react";
|
|
141
|
-
import { notFound as notFound2 } from "next/navigation";
|
|
142
|
-
import { Article, PoweredBy } from "@weekend-studio/easyblog-components";
|
|
143
|
-
async function NextBlogPage(props) {
|
|
144
|
-
try {
|
|
145
|
-
const response = await getBlogPost({
|
|
146
|
-
apiKey: props.config.apiKey,
|
|
147
|
-
projectId: props.config.projectId,
|
|
148
|
-
apiUrl: props.config.apiUrl
|
|
149
|
-
}, props.slug);
|
|
150
|
-
if (!response.blog) return notFound2();
|
|
151
|
-
const post = response.blog;
|
|
152
|
-
const htmlContent = response.html_content;
|
|
153
|
-
const price_id = response.price_id;
|
|
154
|
-
return /* @__PURE__ */ React.createElement("div", { className: `easyblog-scope ${props.darkMode ? "dark" : ""}`, suppressHydrationWarning: true }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", maxWidth: "1200px", marginLeft: "auto", marginRight: "auto" } }, /* @__PURE__ */ React.createElement(
|
|
155
|
-
Article,
|
|
156
|
-
{
|
|
157
|
-
post,
|
|
158
|
-
content: htmlContent,
|
|
159
|
-
style: props.style,
|
|
160
|
-
showAuthor: props.showAuthor,
|
|
161
|
-
showDate: props.showDate,
|
|
162
|
-
showCategory: props.showCategory,
|
|
163
|
-
showTags: props.showTags,
|
|
164
|
-
showToc: props.showToc
|
|
165
|
-
}
|
|
166
|
-
)), price_id == null && /* @__PURE__ */ React.createElement("div", { style: { position: "fixed", bottom: "1rem", right: "1rem", display: "flex", justifyContent: "center", alignItems: "center" } }, /* @__PURE__ */ React.createElement(PoweredBy, null)));
|
|
167
|
-
} catch (error) {
|
|
168
|
-
console.error("Error fetching blog post:", error);
|
|
169
|
-
return notFound2();
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// src/NextBlogListPage.tsx
|
|
174
|
-
import React4 from "react";
|
|
175
|
-
import { ArticleGroup } from "@weekend-studio/easyblog-components";
|
|
176
|
-
|
|
177
|
-
// src/pagination.tsx
|
|
178
|
-
import * as React3 from "react";
|
|
179
|
-
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react";
|
|
180
|
-
|
|
181
|
-
// ../easyblog-components/src/ui/button.tsx
|
|
182
|
-
import * as React2 from "react";
|
|
183
|
-
import { Slot } from "@radix-ui/react-slot";
|
|
184
|
-
import { cva } from "class-variance-authority";
|
|
185
|
-
|
|
186
|
-
// ../easyblog-components/src/utils.ts
|
|
187
|
-
import { clsx } from "clsx";
|
|
188
|
-
import { twMerge } from "tailwind-merge";
|
|
189
|
-
function cn(...inputs) {
|
|
190
|
-
return twMerge(clsx(inputs));
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// ../easyblog-components/src/ui/button.tsx
|
|
194
|
-
var buttonVariants = cva(
|
|
195
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
196
|
-
{
|
|
197
|
-
variants: {
|
|
198
|
-
variant: {
|
|
199
|
-
default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
|
200
|
-
destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
|
201
|
-
outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
|
202
|
-
secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
|
203
|
-
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
204
|
-
link: "text-primary underline-offset-4 hover:underline"
|
|
205
|
-
},
|
|
206
|
-
size: {
|
|
207
|
-
default: "h-9 px-4 py-2",
|
|
208
|
-
sm: "h-8 rounded-md px-3 text-xs",
|
|
209
|
-
lg: "h-10 rounded-md px-8",
|
|
210
|
-
icon: "h-9 w-9"
|
|
211
|
-
}
|
|
212
|
-
},
|
|
213
|
-
defaultVariants: {
|
|
214
|
-
variant: "default",
|
|
215
|
-
size: "default"
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
);
|
|
219
|
-
var Button = React2.forwardRef(
|
|
220
|
-
(_a, ref) => {
|
|
221
|
-
var _b = _a, { className, variant, size, asChild = false } = _b, props = __objRest(_b, ["className", "variant", "size", "asChild"]);
|
|
222
|
-
const Comp = asChild ? Slot : "button";
|
|
223
|
-
return /* @__PURE__ */ React2.createElement(
|
|
224
|
-
Comp,
|
|
225
|
-
__spreadValues({
|
|
226
|
-
className: cn(buttonVariants({ variant, size, className })),
|
|
227
|
-
ref
|
|
228
|
-
}, props)
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
);
|
|
232
|
-
Button.displayName = "Button";
|
|
233
|
-
|
|
234
|
-
// src/pagination.tsx
|
|
235
|
-
var Pagination = (_a) => {
|
|
236
|
-
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
237
|
-
return /* @__PURE__ */ React3.createElement(
|
|
238
|
-
"nav",
|
|
239
|
-
__spreadValues({
|
|
240
|
-
role: "navigation",
|
|
241
|
-
"aria-label": "pagination",
|
|
242
|
-
className: cn("mx-auto flex w-full justify-center", className)
|
|
243
|
-
}, props)
|
|
244
|
-
);
|
|
245
|
-
};
|
|
246
|
-
Pagination.displayName = "Pagination";
|
|
247
|
-
var PaginationContent = React3.forwardRef((_a, ref) => {
|
|
248
|
-
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
249
|
-
return /* @__PURE__ */ React3.createElement(
|
|
250
|
-
"ul",
|
|
251
|
-
__spreadValues({
|
|
252
|
-
ref,
|
|
253
|
-
className: cn("flex flex-row items-center gap-1", className)
|
|
254
|
-
}, props)
|
|
255
|
-
);
|
|
256
|
-
});
|
|
257
|
-
PaginationContent.displayName = "PaginationContent";
|
|
258
|
-
var PaginationItem = React3.forwardRef((_a, ref) => {
|
|
259
|
-
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
260
|
-
return /* @__PURE__ */ React3.createElement("li", __spreadValues({ ref, className: cn("", className) }, props));
|
|
261
|
-
});
|
|
262
|
-
PaginationItem.displayName = "PaginationItem";
|
|
263
|
-
var PaginationLink = (_a) => {
|
|
264
|
-
var _b = _a, {
|
|
265
|
-
className,
|
|
266
|
-
isActive,
|
|
267
|
-
size = "icon"
|
|
268
|
-
} = _b, props = __objRest(_b, [
|
|
269
|
-
"className",
|
|
270
|
-
"isActive",
|
|
271
|
-
"size"
|
|
272
|
-
]);
|
|
273
|
-
return /* @__PURE__ */ React3.createElement(
|
|
274
|
-
"a",
|
|
275
|
-
__spreadValues({
|
|
276
|
-
"aria-current": isActive ? "page" : void 0,
|
|
277
|
-
className: cn(
|
|
278
|
-
buttonVariants({
|
|
279
|
-
variant: isActive ? "outline" : "ghost",
|
|
280
|
-
size
|
|
281
|
-
}),
|
|
282
|
-
className
|
|
283
|
-
)
|
|
284
|
-
}, props)
|
|
285
|
-
);
|
|
286
|
-
};
|
|
287
|
-
PaginationLink.displayName = "PaginationLink";
|
|
288
|
-
var PaginationPrevious = (_a) => {
|
|
289
|
-
var _b = _a, {
|
|
290
|
-
className
|
|
291
|
-
} = _b, props = __objRest(_b, [
|
|
292
|
-
"className"
|
|
293
|
-
]);
|
|
294
|
-
return /* @__PURE__ */ React3.createElement(
|
|
295
|
-
PaginationLink,
|
|
296
|
-
__spreadValues({
|
|
297
|
-
"aria-label": "Go to previous page",
|
|
298
|
-
size: "default",
|
|
299
|
-
className: cn("gap-1 pl-2.5", className)
|
|
300
|
-
}, props),
|
|
301
|
-
/* @__PURE__ */ React3.createElement(ChevronLeft, { className: "h-4 w-4" }),
|
|
302
|
-
/* @__PURE__ */ React3.createElement("span", null, "Previous")
|
|
303
|
-
);
|
|
304
|
-
};
|
|
305
|
-
PaginationPrevious.displayName = "PaginationPrevious";
|
|
306
|
-
var PaginationNext = (_a) => {
|
|
307
|
-
var _b = _a, {
|
|
308
|
-
className
|
|
309
|
-
} = _b, props = __objRest(_b, [
|
|
310
|
-
"className"
|
|
311
|
-
]);
|
|
312
|
-
return /* @__PURE__ */ React3.createElement(
|
|
313
|
-
PaginationLink,
|
|
314
|
-
__spreadValues({
|
|
315
|
-
"aria-label": "Go to next page",
|
|
316
|
-
size: "default",
|
|
317
|
-
className: cn("gap-1 pr-2.5", className)
|
|
318
|
-
}, props),
|
|
319
|
-
/* @__PURE__ */ React3.createElement("span", null, "Next"),
|
|
320
|
-
/* @__PURE__ */ React3.createElement(ChevronRight, { className: "h-4 w-4" })
|
|
321
|
-
);
|
|
322
|
-
};
|
|
323
|
-
PaginationNext.displayName = "PaginationNext";
|
|
324
|
-
var PaginationEllipsis = (_a) => {
|
|
325
|
-
var _b = _a, {
|
|
326
|
-
className
|
|
327
|
-
} = _b, props = __objRest(_b, [
|
|
328
|
-
"className"
|
|
329
|
-
]);
|
|
330
|
-
return /* @__PURE__ */ React3.createElement(
|
|
331
|
-
"span",
|
|
332
|
-
__spreadValues({
|
|
333
|
-
"aria-hidden": true,
|
|
334
|
-
className: cn("flex h-9 w-9 items-center justify-center", className)
|
|
335
|
-
}, props),
|
|
336
|
-
/* @__PURE__ */ React3.createElement(MoreHorizontal, { className: "h-4 w-4" }),
|
|
337
|
-
/* @__PURE__ */ React3.createElement("span", { className: "sr-only" }, "More pages")
|
|
338
|
-
);
|
|
339
|
-
};
|
|
340
|
-
PaginationEllipsis.displayName = "PaginationEllipsis";
|
|
341
|
-
|
|
342
|
-
// src/NextBlogListPage.tsx
|
|
343
|
-
var DEFAULT_BLOG_PER_PAGE = 9;
|
|
344
|
-
async function NextBlogListPage(props) {
|
|
345
|
-
var _a, _b;
|
|
346
|
-
const postsPerPage = ((_a = props.displayOptions) == null ? void 0 : _a.blogPerPage) || DEFAULT_BLOG_PER_PAGE;
|
|
347
|
-
const searchParams = await props.searchParams || {};
|
|
348
|
-
const currentPage = Number(searchParams.page) || 1;
|
|
349
|
-
const queryParams = {
|
|
350
|
-
index: (currentPage - 1) * postsPerPage,
|
|
351
|
-
limit: postsPerPage,
|
|
352
|
-
category: searchParams.category || "",
|
|
353
|
-
tags: ((_b = searchParams.tags) == null ? void 0 : _b.split(",")) || []
|
|
354
|
-
};
|
|
355
|
-
const res = await getBlogPosts(
|
|
356
|
-
props.config,
|
|
357
|
-
queryParams
|
|
358
|
-
);
|
|
359
|
-
const { blogs, total } = res;
|
|
360
|
-
const totalPages = Math.ceil(total / queryParams.limit);
|
|
361
|
-
const visiblePages = getVisiblePages(currentPage, totalPages);
|
|
362
|
-
return /* @__PURE__ */ React4.createElement("div", { className: `easyblog-scope ${props.darkMode ? "dark" : ""}`, suppressHydrationWarning: true }, /* @__PURE__ */ React4.createElement(
|
|
363
|
-
ArticleGroup,
|
|
364
|
-
__spreadValues({
|
|
365
|
-
blogs,
|
|
366
|
-
type: props.type
|
|
367
|
-
}, props.displayOptions)
|
|
368
|
-
), totalPages > 1 && /* @__PURE__ */ React4.createElement(Pagination, { className: "mt-8" }, /* @__PURE__ */ React4.createElement(PaginationContent, null, currentPage > 1 && /* @__PURE__ */ React4.createElement(PaginationItem, null, /* @__PURE__ */ React4.createElement(PaginationPrevious, { href: `/blogs?page=${currentPage - 1}` })), visiblePages.map((pageNum, idx) => pageNum === null ? /* @__PURE__ */ React4.createElement(PaginationItem, { key: `ellipsis-${idx}` }, /* @__PURE__ */ React4.createElement(PaginationEllipsis, null)) : /* @__PURE__ */ React4.createElement(PaginationItem, { key: pageNum }, /* @__PURE__ */ React4.createElement(
|
|
369
|
-
PaginationLink,
|
|
370
|
-
{
|
|
371
|
-
href: `/blogs?page=${pageNum}`,
|
|
372
|
-
isActive: pageNum === currentPage
|
|
373
|
-
},
|
|
374
|
-
pageNum
|
|
375
|
-
))), currentPage < totalPages && /* @__PURE__ */ React4.createElement(PaginationItem, null, /* @__PURE__ */ React4.createElement(PaginationNext, { href: `/blogs?page=${currentPage + 1}` })))));
|
|
376
|
-
}
|
|
377
|
-
export {
|
|
378
|
-
NextBlogListPage,
|
|
379
|
-
NextBlogPage,
|
|
380
|
-
generateMetadata,
|
|
381
|
-
getBlogPaths,
|
|
382
|
-
getBlogPost,
|
|
383
|
-
getBlogPosts
|
|
384
|
-
};
|
|
1
|
+
var V=Object.defineProperty;var b=Object.getOwnPropertySymbols;var j=Object.prototype.hasOwnProperty,M=Object.prototype.propertyIsEnumerable;var S=(t,e,a)=>e in t?V(t,e,{enumerable:!0,configurable:!0,writable:!0,value:a}):t[e]=a,s=(t,e)=>{for(var a in e||(e={}))j.call(e,a)&&S(t,a,e[a]);if(b)for(var a of b(e))M.call(e,a)&&S(t,a,e[a]);return t};var g=(t,e)=>{var a={};for(var o in t)j.call(t,o)&&e.indexOf(o)<0&&(a[o]=t[o]);if(t!=null&&b)for(var o of b(t))e.indexOf(o)<0&&M.call(t,o)&&(a[o]=t[o]);return a};import{cache as O}from"react";import{notFound as Q}from"next/navigation";async function A(t){try{let e=await fetch(`${t.apiUrl}/exchange-token`,{method:"POST",headers:{Authorization:`Bearer ${t.apiKey}`,"x-project-id":t.projectId}});if(!e.ok)throw console.error("Failed to exchange token:",e),new Error("Failed to authenticate");return(await e.json()).token}catch(e){return console.error("Failed to exchange token:",e),null}}var D=t=>t?new Date(t).toISOString().split("T")[0]:"",F=(t,e)=>e<=7?Array.from({length:e},(a,o)=>o+1):t<=3?[1,2,3,4,5,null,e]:t>=e-2?[1,null,e-4,e-3,e-2,e-1,e]:[1,null,t-1,t,t+1,null,e];var U=O(async t=>A(t));async function x(t,e={}){let a=await U(t),o=new URLSearchParams(Object.entries(e).map(([u,d])=>[u,String(d)])).toString(),n=`${t.apiUrl}/sdk/blogs${o?`?${o}`:""}`,i=await fetch(n,{headers:{Authorization:`Bearer ${a}`,"x-project-id":t.projectId},next:{revalidate:3600}});if(!i.ok)throw console.error("Failed to fetch blog posts:",i),new Error(`Failed to fetch blog posts: ${i.status} ${i.statusText}`);return await i.json()}async function w(t,e){let a=await U(t),o=await fetch(`${t.apiUrl}/sdk/blogs/${e}`,{headers:{Authorization:`Bearer ${a}`,"x-project-id":t.projectId},next:{revalidate:3600}});if(!o.ok)throw new Error(`Failed to fetch blog post: ${o.status} ${o.statusText}`);return o.json()}async function H(t){let e=await x(t,{index:0,limit:1e4});return e.blogs?e.blogs.map(a=>({slug:a.slug})):[]}async function G(t,e){var a,o;if(e){let n=await w(t,e);return n?{title:n.title,description:(a=n.excerpt)==null?void 0:a.substring(0,160),openGraph:{title:n.title,description:(o=n.excerpt)==null?void 0:o.substring(0,160),type:"article",publishedTime:D(n.created_at),tags:n.tags}}:Q()}return{title:"Blog",description:"Read our latest blog posts",openGraph:{title:"Blog",description:"Read our latest blog posts",type:"website"}}}import h from"react";import{notFound as R}from"next/navigation";import{Article as q,PoweredBy as K}from"@weekend-studio/easyblog-components";async function W(t){try{let e=await w({apiKey:t.config.apiKey,projectId:t.config.projectId,apiUrl:t.config.apiUrl},t.slug);if(!e.blog)return R();let a=e.blog,o=e.html_content,n=e.price_id;return h.createElement("div",{className:`${t.darkMode?"dark":""}`,suppressHydrationWarning:!0},h.createElement("div",{style:{display:"flex",maxWidth:"1200px",marginLeft:"auto",marginRight:"auto"}},h.createElement(q,{post:a,content:o,style:t.style,showAuthor:t.showAuthor,showDate:t.showDate,showCategory:t.showCategory,showTags:t.showTags,showToc:t.showToc})),n==null&&h.createElement("div",{style:{position:"fixed",bottom:"1rem",right:"1rem",display:"flex",justifyContent:"center",alignItems:"center"}},h.createElement(K,null)))}catch(e){return console.error("Error fetching blog post:",e),R()}}import l from"react";import{ArticleGroup as nt}from"@weekend-studio/easyblog-components";import*as r from"react";import{ChevronLeft as et,ChevronRight as ot,MoreHorizontal as at}from"lucide-react";import*as B from"react";import{Slot as Y}from"@radix-ui/react-slot";import{cva as Z}from"class-variance-authority";import{clsx as J}from"clsx";import{twMerge as X}from"tailwind-merge";function c(...t){return X(J(t))}var k=Z("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",{variants:{variant:{default:"bg-primary text-primary-foreground shadow hover:bg-primary/90",destructive:"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",outline:"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",secondary:"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",ghost:"hover:bg-accent hover:text-accent-foreground",link:"text-primary underline-offset-4 hover:underline"},size:{default:"h-9 px-4 py-2",sm:"h-8 rounded-md px-3 text-xs",lg:"h-10 rounded-md px-8",icon:"h-9 w-9"}},defaultVariants:{variant:"default",size:"default"}}),tt=B.forwardRef((v,i)=>{var u=v,{className:t,variant:e,size:a,asChild:o=!1}=u,n=g(u,["className","variant","size","asChild"]);return B.createElement(o?Y:"button",s({className:c(k({variant:e,size:a,className:t})),ref:i},n))});tt.displayName="Button";var C=a=>{var o=a,{className:t}=o,e=g(o,["className"]);return r.createElement("nav",s({role:"navigation","aria-label":"pagination",className:c("mx-auto flex w-full justify-center",t)},e))};C.displayName="Pagination";var N=r.forwardRef((o,a)=>{var n=o,{className:t}=n,e=g(n,["className"]);return r.createElement("ul",s({ref:a,className:c("flex flex-row items-center gap-1",t)},e))});N.displayName="PaginationContent";var f=r.forwardRef((o,a)=>{var n=o,{className:t}=n,e=g(n,["className"]);return r.createElement("li",s({ref:a,className:c("",t)},e))});f.displayName="PaginationItem";var y=n=>{var i=n,{className:t,isActive:e,size:a="icon"}=i,o=g(i,["className","isActive","size"]);return r.createElement("a",s({"aria-current":e?"page":void 0,className:c(k({variant:e?"outline":"ghost",size:a}),t)},o))};y.displayName="PaginationLink";var E=a=>{var o=a,{className:t}=o,e=g(o,["className"]);return r.createElement(y,s({"aria-label":"Go to previous page",size:"default",className:c("gap-1 pl-2.5",t)},e),r.createElement(et,{className:"h-4 w-4"}),r.createElement("span",null,"Previous"))};E.displayName="PaginationPrevious";var L=a=>{var o=a,{className:t}=o,e=g(o,["className"]);return r.createElement(y,s({"aria-label":"Go to next page",size:"default",className:c("gap-1 pr-2.5",t)},e),r.createElement("span",null,"Next"),r.createElement(ot,{className:"h-4 w-4"}))};L.displayName="PaginationNext";var I=a=>{var o=a,{className:t}=o,e=g(o,["className"]);return r.createElement("span",s({"aria-hidden":!0,className:c("flex h-9 w-9 items-center justify-center",t)},e),r.createElement(at,{className:"h-4 w-4"}),r.createElement("span",{className:"sr-only"},"More pages"))};I.displayName="PaginationEllipsis";var rt=9;async function it(t){var T,$;let e=((T=t.displayOptions)==null?void 0:T.blogPerPage)||rt,a=await t.searchParams||{},o=Number(a.page)||1,n={index:(o-1)*e,limit:e,category:a.category||"",tags:(($=a.tags)==null?void 0:$.split(","))||[]},i=await x(t.config,n),{blogs:v,total:u}=i,d=Math.ceil(u/n.limit),_=F(o,d);return l.createElement("div",{className:`${t.darkMode?"dark":""}`,suppressHydrationWarning:!0},l.createElement(nt,s({blogs:v,type:t.type},t.displayOptions)),d>1&&l.createElement(C,{className:"mt-8"},l.createElement(N,null,o>1&&l.createElement(f,null,l.createElement(E,{href:`/blogs?page=${o-1}`})),_.map((P,z)=>P===null?l.createElement(f,{key:`ellipsis-${z}`},l.createElement(I,null)):l.createElement(f,{key:P},l.createElement(y,{href:`/blogs?page=${P}`,isActive:P===o},P))),o<d&&l.createElement(f,null,l.createElement(L,{href:`/blogs?page=${o+1}`})))))}export{it as NextBlogListPage,W as NextBlogPage,G as generateMetadata,H as getBlogPaths,w as getBlogPost,x as getBlogPosts};
|
|
385
2
|
//# sourceMappingURL=app-index.mjs.map
|
package/dist/app-index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/NextAppRouterUtils.ts","../src/BaseUtils.ts","../src/utils.ts","../src/NextBlogPage.tsx","../src/NextBlogListPage.tsx","../src/pagination.tsx","../../easyblog-components/src/ui/button.tsx","../../easyblog-components/src/utils.ts"],"sourcesContent":["import { cache } from \"react\";\nimport { EasyBlogConfig, IQueryParams } from \"./models\";\nimport { Metadata } from \"next\";\nimport { notFound } from \"next/navigation\";\nimport { exchangeToken } from './BaseUtils';\nimport { getFormattedDate } from \"./utils\";\n\n// Cached token getter\nconst getAuthToken = cache(async (config: EasyBlogConfig): Promise<string | null> => {\n return exchangeToken(config);\n});\n \n// Server-side data fetching functions\nasync function getBlogPosts(config: EasyBlogConfig, params: IQueryParams = {}) {\n const token = await getAuthToken(config);\n\n const queryString = new URLSearchParams(\n Object.entries(params).map(([key, value]) => [key, String(value)])\n ).toString();\n\n const url = `${config.apiUrl}/sdk/blogs${queryString ? `?${queryString}` : ''}`;\n\n const response = await fetch(url, {\n headers: { \n 'Authorization': `Bearer ${token}`,\n 'x-project-id': config.projectId\n },\n next: { revalidate: 3600 }\n });\n\n if (!response.ok) {\n console.error('Failed to fetch blog posts:', response);\n throw new Error(`Failed to fetch blog posts: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json();\n return data;\n}\n\nasync function getBlogPost(config: EasyBlogConfig, slug: string) {\n const token = await getAuthToken(config);\n\n const response = await fetch(`${config.apiUrl}/sdk/blogs/${slug}`, {\n headers: { \n 'Authorization': `Bearer ${token}`,\n 'x-project-id': config.projectId\n },\n next: { revalidate: 3600 }\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch blog post: ${response.status} ${response.statusText}`);\n }\n\n return response.json();\n}\n\nasync function getBlogPaths(config: EasyBlogConfig) {\n const res = await getBlogPosts(config, { index: 0, limit: 10000 });\n if (!res.blogs) return [];\n return res.blogs.map((blog: any) => ({ slug: blog.slug }));\n}\n\nasync function generateMetadata(config: EasyBlogConfig, slug?: string): Promise<Metadata> {\n if (slug) {\n const post = await getBlogPost(config, slug);\n if (!post) return notFound();\n\n return {\n title: post.title,\n description: post.excerpt?.substring(0, 160),\n openGraph: {\n title: post.title,\n description: post.excerpt?.substring(0, 160),\n type: 'article',\n publishedTime: getFormattedDate(post.created_at),\n tags: post.tags,\n },\n };\n }\n\n return {\n title: 'Blog',\n description: 'Read our latest blog posts',\n openGraph: {\n title: 'Blog',\n description: 'Read our latest blog posts',\n type: 'website',\n },\n };\n}\n\n// Server exports\nexport {\n generateMetadata,\n getBlogPost,\n getBlogPosts,\n getBlogPaths,\n};\n","// Base functionality shared between both routers\nimport { EasyBlogConfig, IQueryParams } from \"./models\";\n\nexport async function exchangeToken(config: EasyBlogConfig): Promise<string | null> {\n try {\n const response = await fetch(`${config.apiUrl}/exchange-token`, {\n method: 'POST',\n headers: { \n 'Authorization': `Bearer ${config.apiKey}`,\n 'x-project-id': config.projectId\n }\n });\n\n if (!response.ok) {\n console.error('Failed to exchange token:', response);\n throw new Error('Failed to authenticate');\n }\n\n const data = await response.json();\n return data.token;\n } catch (error) {\n console.error('Failed to exchange token:', error);\n return null;\n }\n}\n\n\nexport async function getBlogPostsBase(config: EasyBlogConfig, params: IQueryParams = {}) {\n const token = await exchangeToken(config);\n\n const queryString = new URLSearchParams(\n Object.entries(params).map(([key, value]) => [key, String(value)])\n ).toString();\n\n const url = `${config.apiUrl}/sdk/blogs${queryString ? `?${queryString}` : ''}`;\n\n return { url, token };\n}\n\nexport async function getBlogPostBase(config: EasyBlogConfig, slug: string) {\n const token = await exchangeToken(config);\n const url = `${config.apiUrl}/sdk/blogs/${slug}`;\n return { url, token };\n}","import { IQueryParams } from \"./models\";\n\nexport function buildQueryParams(params: IQueryParams): string {\n const queryParams = new URLSearchParams();\n params.index && queryParams.set('index', params.index.toString());\n params.limit && queryParams.set('limit', params.limit.toString());\n if (params.category) queryParams.set('category', params.category);\n if (params.tags) queryParams.set('tags', [params.tags].join(','));\n return queryParams.toString();\n}\n\nexport const getFormattedDate = (date: Date) => {\n if (!date) return '';\n return new Date(date).toISOString().split('T')[0];\n}\n\n// Helper function to generate visible page numbers\nexport const getVisiblePages = (current: number, total: number) => {\n if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1);\n \n if (current <= 3) return [1, 2, 3, 4, 5, null, total];\n if (current >= total - 2) return [1, null, total - 4, total - 3, total - 2, total - 1, total];\n \n return [1, null, current - 1, current, current + 1, null, total];\n};","import React from 'react';\nimport { notFound } from 'next/navigation';\nimport { Article, PoweredBy } from '@weekend-studio/easyblog-components';\nimport { EasyBlogConfig } from './models';\nimport { getBlogPost } from './NextAppRouterUtils';\n\ninterface NextBlogPageProps {\n config: EasyBlogConfig;\n darkMode?: boolean;\n showAuthor?: boolean;\n showDate?: boolean;\n showCategory?: boolean;\n showTags?: boolean;\n slug: string;\n style?: React.CSSProperties;\n showToc?: boolean;\n}\n\nexport async function NextBlogPage(props: NextBlogPageProps) {\n try {\n const response = await getBlogPost({ \n apiKey: props.config.apiKey, \n projectId: props.config.projectId,\n apiUrl: props.config.apiUrl\n }, props.slug);\n if (!response.blog) return notFound();\n const post = response.blog;\n const htmlContent = response.html_content;\n const price_id = response.price_id;\n\n return (\n <div className={`easyblog-scope ${props.darkMode ? 'dark' : ''}`} suppressHydrationWarning>\n <div style={{ display: 'flex', maxWidth: '1200px', marginLeft: 'auto', marginRight: 'auto' }}>\n <Article \n post={post} \n content={htmlContent}\n style={props.style}\n showAuthor={props.showAuthor}\n showDate={props.showDate}\n showCategory={props.showCategory}\n showTags={props.showTags}\n showToc={props.showToc}\n />\n </div>\n {price_id == null && \n <div style={{ position: 'fixed', bottom: '1rem', right: '1rem', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>\n <PoweredBy />\n </div>\n }\n </div>\n );\n } catch (error) {\n console.error('Error fetching blog post:', error);\n return notFound();\n }\n}\n","import React from 'react';\nimport { getBlogPosts } from './NextAppRouterUtils';\nimport { ArticleGroup } from '@weekend-studio/easyblog-components';\nimport { EasyBlogConfig, IQueryParams } from './models';\nimport {\n Pagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n PaginationNext,\n PaginationPrevious,\n} from \"./pagination\"\nimport { getVisiblePages } from './utils';\n\nconst DEFAULT_BLOG_PER_PAGE = 9;\ninterface NextBlogListPageProps {\n config: EasyBlogConfig;\n darkMode?: boolean;\n type: 'grid' | 'list';\n searchParams?: {\n page?: string;\n category?: string;\n tags?: string;\n };\n displayOptions?: {\n showThumbnail?: boolean;\n showReadingTime?: boolean;\n showExcerpt?: boolean;\n showTags?: boolean;\n showDate?: boolean;\n showAuthor?: boolean;\n showCategory?: boolean;\n isNextPage?: boolean;\n blogPerPage?: number;\n }\n}\n\nexport async function NextBlogListPage(props: NextBlogListPageProps) {\n const postsPerPage = props.displayOptions?.blogPerPage || DEFAULT_BLOG_PER_PAGE;\n const searchParams = await props.searchParams || {};\n const currentPage = Number(searchParams.page) || 1;\n\n const queryParams: IQueryParams = {\n index: (currentPage - 1) * postsPerPage,\n limit: postsPerPage,\n category: searchParams.category || '',\n tags: searchParams.tags?.split(',') || []\n }\n\n const res = await getBlogPosts(\n props.config, \n queryParams\n );\n\n const { blogs, total } = res;\n\n const totalPages = Math.ceil(total / queryParams.limit!);\n\n const visiblePages = getVisiblePages(currentPage, totalPages);\n\n return (\n <div className={`easyblog-scope ${props.darkMode ? 'dark' : ''}`} suppressHydrationWarning>\n <ArticleGroup\n blogs={blogs} \n type={props.type}\n {...props.displayOptions}\n />\n\n {totalPages > 1 && (\n <Pagination className=\"mt-8\">\n <PaginationContent>\n {currentPage > 1 && (\n <PaginationItem>\n <PaginationPrevious href={`/blogs?page=${currentPage - 1}`} />\n </PaginationItem>\n )}\n\n {visiblePages.map((pageNum, idx) => (\n pageNum === null ? (\n <PaginationItem key={`ellipsis-${idx}`}>\n <PaginationEllipsis />\n </PaginationItem>\n ) : (\n <PaginationItem key={pageNum}>\n <PaginationLink\n href={`/blogs?page=${pageNum}`}\n isActive={pageNum === currentPage}\n >\n {pageNum}\n </PaginationLink>\n </PaginationItem>\n )\n ))}\n\n {currentPage < totalPages && (\n <PaginationItem>\n <PaginationNext href={`/blogs?page=${currentPage + 1}`} />\n </PaginationItem>\n )}\n </PaginationContent>\n </Pagination>\n )}\n </div>\n );\n}\n","import * as React from \"react\"\nimport { ChevronLeft, ChevronRight, MoreHorizontal } from \"lucide-react\"\nimport { ButtonProps, buttonVariants } from \"../../easyblog-components/src/ui/button\"\nimport { cn } from \"../../easyblog-components/src/utils\"\n\nconst Pagination = ({ className, ...props }: React.ComponentProps<\"nav\">) => (\n <nav\n role=\"navigation\"\n aria-label=\"pagination\"\n className={cn(\"mx-auto flex w-full justify-center\", className)}\n {...props}\n />\n)\nPagination.displayName = \"Pagination\"\n\nconst PaginationContent = React.forwardRef<\n HTMLUListElement,\n React.ComponentProps<\"ul\">\n>(({ className, ...props }, ref) => (\n <ul\n ref={ref}\n className={cn(\"flex flex-row items-center gap-1\", className)}\n {...props}\n />\n))\nPaginationContent.displayName = \"PaginationContent\"\n\nconst PaginationItem = React.forwardRef<\n HTMLLIElement,\n React.ComponentProps<\"li\">\n>(({ className, ...props }, ref) => (\n <li ref={ref} className={cn(\"\", className)} {...props} />\n))\nPaginationItem.displayName = \"PaginationItem\"\n\ntype PaginationLinkProps = {\n isActive?: boolean\n} & Pick<ButtonProps, \"size\"> &\n React.ComponentProps<any>\n\nconst PaginationLink = ({\n className,\n isActive,\n size = \"icon\",\n ...props\n}: PaginationLinkProps) => (\n <a\n aria-current={isActive ? \"page\" : undefined}\n className={cn(\n buttonVariants({\n variant: isActive ? \"outline\" : \"ghost\",\n size,\n }),\n className\n )}\n {...props}\n />\n)\nPaginationLink.displayName = \"PaginationLink\"\n\nconst PaginationPrevious = ({\n className,\n ...props\n}: React.ComponentProps<typeof PaginationLink>) => (\n <PaginationLink\n aria-label=\"Go to previous page\"\n size=\"default\"\n className={cn(\"gap-1 pl-2.5\", className)}\n {...props}\n >\n <ChevronLeft className=\"h-4 w-4\" />\n <span>Previous</span>\n </PaginationLink>\n)\nPaginationPrevious.displayName = \"PaginationPrevious\"\n\nconst PaginationNext = ({\n className,\n ...props\n}: React.ComponentProps<typeof PaginationLink>) => (\n <PaginationLink\n aria-label=\"Go to next page\"\n size=\"default\"\n className={cn(\"gap-1 pr-2.5\", className)}\n {...props}\n >\n <span>Next</span>\n <ChevronRight className=\"h-4 w-4\" />\n </PaginationLink>\n)\nPaginationNext.displayName = \"PaginationNext\"\n\nconst PaginationEllipsis = ({\n className,\n ...props\n}: React.ComponentProps<\"span\">) => (\n <span\n aria-hidden\n className={cn(\"flex h-9 w-9 items-center justify-center\", className)}\n {...props}\n >\n <MoreHorizontal className=\"h-4 w-4\" />\n <span className=\"sr-only\">More pages</span>\n </span>\n)\nPaginationEllipsis.displayName = \"PaginationEllipsis\"\n\nexport {\n Pagination,\n PaginationContent,\n PaginationLink,\n PaginationItem,\n PaginationPrevious,\n PaginationNext,\n PaginationEllipsis,\n}\n","import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"../utils\"\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default:\n \"bg-primary text-primary-foreground shadow hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90\",\n outline:\n \"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n sm: \"h-8 rounded-md px-3 text-xs\",\n lg: \"h-10 rounded-md px-8\",\n icon: \"h-9 w-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\"\n return (\n <Comp\n className={cn(buttonVariants({ variant, size, className }))}\n ref={ref}\n {...props}\n />\n )\n }\n)\nButton.displayName = \"Button\"\n\nexport { Button, buttonVariants }\n","import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n\nexport const getFormattedDate = (date: Date) => {\n if (!date) return '';\n return new Date(date).toISOString().split('T')[0];\n}"],"mappings":"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","names":["notFound","notFound","React","React","React","React"]}
|
|
1
|
+
{"version":3,"sources":["../src/NextAppRouterUtils.ts","../src/BaseUtils.ts","../src/utils.ts","../src/NextBlogPage.tsx","../src/NextBlogListPage.tsx","../src/pagination.tsx","../../easyblog-components/src/ui/button.tsx","../../easyblog-components/src/utils.ts"],"sourcesContent":["import { cache } from \"react\";\nimport { EasyBlogConfig, IQueryParams } from \"./models\";\nimport { Metadata } from \"next\";\nimport { notFound } from \"next/navigation\";\nimport { exchangeToken } from './BaseUtils';\nimport { getFormattedDate } from \"./utils\";\n\n// Cached token getter\nconst getAuthToken = cache(async (config: EasyBlogConfig): Promise<string | null> => {\n return exchangeToken(config);\n});\n \n// Server-side data fetching functions\nasync function getBlogPosts(config: EasyBlogConfig, params: IQueryParams = {}) {\n const token = await getAuthToken(config);\n\n const queryString = new URLSearchParams(\n Object.entries(params).map(([key, value]) => [key, String(value)])\n ).toString();\n\n const url = `${config.apiUrl}/sdk/blogs${queryString ? `?${queryString}` : ''}`;\n\n const response = await fetch(url, {\n headers: { \n 'Authorization': `Bearer ${token}`,\n 'x-project-id': config.projectId\n },\n next: { revalidate: 3600 }\n });\n\n if (!response.ok) {\n console.error('Failed to fetch blog posts:', response);\n throw new Error(`Failed to fetch blog posts: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json();\n return data;\n}\n\nasync function getBlogPost(config: EasyBlogConfig, slug: string) {\n const token = await getAuthToken(config);\n\n const response = await fetch(`${config.apiUrl}/sdk/blogs/${slug}`, {\n headers: { \n 'Authorization': `Bearer ${token}`,\n 'x-project-id': config.projectId\n },\n next: { revalidate: 3600 }\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch blog post: ${response.status} ${response.statusText}`);\n }\n\n return response.json();\n}\n\nasync function getBlogPaths(config: EasyBlogConfig) {\n const res = await getBlogPosts(config, { index: 0, limit: 10000 });\n if (!res.blogs) return [];\n return res.blogs.map((blog: any) => ({ slug: blog.slug }));\n}\n\nasync function generateMetadata(config: EasyBlogConfig, slug?: string): Promise<Metadata> {\n if (slug) {\n const post = await getBlogPost(config, slug);\n if (!post) return notFound();\n\n return {\n title: post.title,\n description: post.excerpt?.substring(0, 160),\n openGraph: {\n title: post.title,\n description: post.excerpt?.substring(0, 160),\n type: 'article',\n publishedTime: getFormattedDate(post.created_at),\n tags: post.tags,\n },\n };\n }\n\n return {\n title: 'Blog',\n description: 'Read our latest blog posts',\n openGraph: {\n title: 'Blog',\n description: 'Read our latest blog posts',\n type: 'website',\n },\n };\n}\n\n// Server exports\nexport {\n generateMetadata,\n getBlogPost,\n getBlogPosts,\n getBlogPaths,\n};\n","// Base functionality shared between both routers\nimport { EasyBlogConfig, IQueryParams } from \"./models\";\n\nexport async function exchangeToken(config: EasyBlogConfig): Promise<string | null> {\n try {\n const response = await fetch(`${config.apiUrl}/exchange-token`, {\n method: 'POST',\n headers: { \n 'Authorization': `Bearer ${config.apiKey}`,\n 'x-project-id': config.projectId\n }\n });\n\n if (!response.ok) {\n console.error('Failed to exchange token:', response);\n throw new Error('Failed to authenticate');\n }\n\n const data = await response.json();\n return data.token;\n } catch (error) {\n console.error('Failed to exchange token:', error);\n return null;\n }\n}\n\n\nexport async function getBlogPostsBase(config: EasyBlogConfig, params: IQueryParams = {}) {\n const token = await exchangeToken(config);\n\n const queryString = new URLSearchParams(\n Object.entries(params).map(([key, value]) => [key, String(value)])\n ).toString();\n\n const url = `${config.apiUrl}/sdk/blogs${queryString ? `?${queryString}` : ''}`;\n\n return { url, token };\n}\n\nexport async function getBlogPostBase(config: EasyBlogConfig, slug: string) {\n const token = await exchangeToken(config);\n const url = `${config.apiUrl}/sdk/blogs/${slug}`;\n return { url, token };\n}","import { IQueryParams } from \"./models\";\n\nexport function buildQueryParams(params: IQueryParams): string {\n const queryParams = new URLSearchParams();\n params.index && queryParams.set('index', params.index.toString());\n params.limit && queryParams.set('limit', params.limit.toString());\n if (params.category) queryParams.set('category', params.category);\n if (params.tags) queryParams.set('tags', [params.tags].join(','));\n return queryParams.toString();\n}\n\nexport const getFormattedDate = (date: Date) => {\n if (!date) return '';\n return new Date(date).toISOString().split('T')[0];\n}\n\n// Helper function to generate visible page numbers\nexport const getVisiblePages = (current: number, total: number) => {\n if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1);\n \n if (current <= 3) return [1, 2, 3, 4, 5, null, total];\n if (current >= total - 2) return [1, null, total - 4, total - 3, total - 2, total - 1, total];\n \n return [1, null, current - 1, current, current + 1, null, total];\n};","import React from 'react';\nimport { notFound } from 'next/navigation';\nimport { Article, PoweredBy } from '@weekend-studio/easyblog-components';\nimport { EasyBlogConfig } from './models';\nimport { getBlogPost } from './NextAppRouterUtils';\n\ninterface NextBlogPageProps {\n config: EasyBlogConfig;\n darkMode?: boolean;\n showAuthor?: boolean;\n showDate?: boolean;\n showCategory?: boolean;\n showTags?: boolean;\n slug: string;\n style?: React.CSSProperties;\n showToc?: boolean;\n}\n\nexport async function NextBlogPage(props: NextBlogPageProps) {\n try {\n const response = await getBlogPost({ \n apiKey: props.config.apiKey, \n projectId: props.config.projectId,\n apiUrl: props.config.apiUrl\n }, props.slug);\n if (!response.blog) return notFound();\n const post = response.blog;\n const htmlContent = response.html_content;\n const price_id = response.price_id;\n\n return (\n <div className={`${props.darkMode ? 'dark' : ''}`} suppressHydrationWarning>\n <div style={{ display: 'flex', maxWidth: '1200px', marginLeft: 'auto', marginRight: 'auto' }}>\n <Article \n post={post} \n content={htmlContent}\n style={props.style}\n showAuthor={props.showAuthor}\n showDate={props.showDate}\n showCategory={props.showCategory}\n showTags={props.showTags}\n showToc={props.showToc}\n />\n </div>\n {price_id == null && \n <div style={{ position: 'fixed', bottom: '1rem', right: '1rem', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>\n <PoweredBy />\n </div>\n }\n </div>\n );\n } catch (error) {\n console.error('Error fetching blog post:', error);\n return notFound();\n }\n}\n","import React from 'react';\nimport { getBlogPosts } from './NextAppRouterUtils';\nimport { ArticleGroup } from '@weekend-studio/easyblog-components';\nimport { EasyBlogConfig, IQueryParams } from './models';\nimport {\n Pagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n PaginationNext,\n PaginationPrevious,\n} from \"./pagination\"\nimport { getVisiblePages } from './utils';\n\nconst DEFAULT_BLOG_PER_PAGE = 9;\ninterface NextBlogListPageProps {\n config: EasyBlogConfig;\n darkMode?: boolean;\n type: 'grid' | 'list';\n searchParams?: {\n page?: string;\n category?: string;\n tags?: string;\n };\n displayOptions?: {\n showThumbnail?: boolean;\n showReadingTime?: boolean;\n showExcerpt?: boolean;\n showTags?: boolean;\n showDate?: boolean;\n showAuthor?: boolean;\n showCategory?: boolean;\n isNextPage?: boolean;\n blogPerPage?: number;\n }\n}\n\nexport async function NextBlogListPage(props: NextBlogListPageProps) {\n const postsPerPage = props.displayOptions?.blogPerPage || DEFAULT_BLOG_PER_PAGE;\n const searchParams = await props.searchParams || {};\n const currentPage = Number(searchParams.page) || 1;\n\n const queryParams: IQueryParams = {\n index: (currentPage - 1) * postsPerPage,\n limit: postsPerPage,\n category: searchParams.category || '',\n tags: searchParams.tags?.split(',') || []\n }\n\n const res = await getBlogPosts(\n props.config, \n queryParams\n );\n\n const { blogs, total } = res;\n\n const totalPages = Math.ceil(total / queryParams.limit!);\n\n const visiblePages = getVisiblePages(currentPage, totalPages);\n\n return (\n <div className={`${props.darkMode ? 'dark' : ''}`} suppressHydrationWarning>\n <ArticleGroup\n blogs={blogs} \n type={props.type}\n {...props.displayOptions}\n />\n\n {totalPages > 1 && (\n <Pagination className=\"mt-8\">\n <PaginationContent>\n {currentPage > 1 && (\n <PaginationItem>\n <PaginationPrevious href={`/blogs?page=${currentPage - 1}`} />\n </PaginationItem>\n )}\n\n {visiblePages.map((pageNum, idx) => (\n pageNum === null ? (\n <PaginationItem key={`ellipsis-${idx}`}>\n <PaginationEllipsis />\n </PaginationItem>\n ) : (\n <PaginationItem key={pageNum}>\n <PaginationLink\n href={`/blogs?page=${pageNum}`}\n isActive={pageNum === currentPage}\n >\n {pageNum}\n </PaginationLink>\n </PaginationItem>\n )\n ))}\n\n {currentPage < totalPages && (\n <PaginationItem>\n <PaginationNext href={`/blogs?page=${currentPage + 1}`} />\n </PaginationItem>\n )}\n </PaginationContent>\n </Pagination>\n )}\n </div>\n );\n}\n","import * as React from \"react\"\nimport { ChevronLeft, ChevronRight, MoreHorizontal } from \"lucide-react\"\nimport { ButtonProps, buttonVariants } from \"../../easyblog-components/src/ui/button\"\nimport { cn } from \"../../easyblog-components/src/utils\"\n\nconst Pagination = ({ className, ...props }: React.ComponentProps<\"nav\">) => (\n <nav\n role=\"navigation\"\n aria-label=\"pagination\"\n className={cn(\"mx-auto flex w-full justify-center\", className)}\n {...props}\n />\n)\nPagination.displayName = \"Pagination\"\n\nconst PaginationContent = React.forwardRef<\n HTMLUListElement,\n React.ComponentProps<\"ul\">\n>(({ className, ...props }, ref) => (\n <ul\n ref={ref}\n className={cn(\"flex flex-row items-center gap-1\", className)}\n {...props}\n />\n))\nPaginationContent.displayName = \"PaginationContent\"\n\nconst PaginationItem = React.forwardRef<\n HTMLLIElement,\n React.ComponentProps<\"li\">\n>(({ className, ...props }, ref) => (\n <li ref={ref} className={cn(\"\", className)} {...props} />\n))\nPaginationItem.displayName = \"PaginationItem\"\n\ntype PaginationLinkProps = {\n isActive?: boolean\n} & Pick<ButtonProps, \"size\"> &\n React.ComponentProps<any>\n\nconst PaginationLink = ({\n className,\n isActive,\n size = \"icon\",\n ...props\n}: PaginationLinkProps) => (\n <a\n aria-current={isActive ? \"page\" : undefined}\n className={cn(\n buttonVariants({\n variant: isActive ? \"outline\" : \"ghost\",\n size,\n }),\n className\n )}\n {...props}\n />\n)\nPaginationLink.displayName = \"PaginationLink\"\n\nconst PaginationPrevious = ({\n className,\n ...props\n}: React.ComponentProps<typeof PaginationLink>) => (\n <PaginationLink\n aria-label=\"Go to previous page\"\n size=\"default\"\n className={cn(\"gap-1 pl-2.5\", className)}\n {...props}\n >\n <ChevronLeft className=\"h-4 w-4\" />\n <span>Previous</span>\n </PaginationLink>\n)\nPaginationPrevious.displayName = \"PaginationPrevious\"\n\nconst PaginationNext = ({\n className,\n ...props\n}: React.ComponentProps<typeof PaginationLink>) => (\n <PaginationLink\n aria-label=\"Go to next page\"\n size=\"default\"\n className={cn(\"gap-1 pr-2.5\", className)}\n {...props}\n >\n <span>Next</span>\n <ChevronRight className=\"h-4 w-4\" />\n </PaginationLink>\n)\nPaginationNext.displayName = \"PaginationNext\"\n\nconst PaginationEllipsis = ({\n className,\n ...props\n}: React.ComponentProps<\"span\">) => (\n <span\n aria-hidden\n className={cn(\"flex h-9 w-9 items-center justify-center\", className)}\n {...props}\n >\n <MoreHorizontal className=\"h-4 w-4\" />\n <span className=\"sr-only\">More pages</span>\n </span>\n)\nPaginationEllipsis.displayName = \"PaginationEllipsis\"\n\nexport {\n Pagination,\n PaginationContent,\n PaginationLink,\n PaginationItem,\n PaginationPrevious,\n PaginationNext,\n PaginationEllipsis,\n}\n","import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"../utils\"\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default:\n \"bg-primary text-primary-foreground shadow hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90\",\n outline:\n \"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n sm: \"h-8 rounded-md px-3 text-xs\",\n lg: \"h-10 rounded-md px-8\",\n icon: \"h-9 w-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\"\n return (\n <Comp\n className={cn(buttonVariants({ variant, size, className }))}\n ref={ref}\n {...props}\n />\n )\n }\n)\nButton.displayName = \"Button\"\n\nexport { Button, buttonVariants }\n","import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n\nexport const getFormattedDate = (date: Date) => {\n if (!date) return '';\n return new Date(date).toISOString().split('T')[0];\n}"],"mappings":"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","names":["cache","notFound","exchangeToken","config","response","error","getFormattedDate","date","getVisiblePages","current","total","_","i","getAuthToken","cache","config","exchangeToken","getBlogPosts","params","token","queryString","key","value","url","response","getBlogPost","slug","getBlogPaths","res","blog","generateMetadata","_a","_b","post","getFormattedDate","notFound","React","notFound","Article","PoweredBy","NextBlogPage","props","response","getBlogPost","notFound","post","htmlContent","price_id","React","Article","PoweredBy","error","React","ArticleGroup","React","ChevronLeft","ChevronRight","MoreHorizontal","React","Slot","cva","clsx","twMerge","cn","inputs","buttonVariants","cva","Button","_a","ref","_b","className","variant","size","asChild","props","__objRest","Slot","__spreadValues","cn","Pagination","_a","_b","className","props","__objRest","__spreadValues","cn","PaginationContent","ref","PaginationItem","PaginationLink","isActive","size","buttonVariants","PaginationPrevious","ChevronLeft","PaginationNext","ChevronRight","PaginationEllipsis","MoreHorizontal","DEFAULT_BLOG_PER_PAGE","NextBlogListPage","props","_a","_b","postsPerPage","searchParams","currentPage","queryParams","res","getBlogPosts","blogs","total","totalPages","visiblePages","getVisiblePages","React","ArticleGroup","__spreadValues","Pagination","PaginationContent","PaginationItem","PaginationPrevious","pageNum","idx","PaginationEllipsis","PaginationLink","PaginationNext"]}
|