@weekend-studio/easyblog-next 0.0.1

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/index.mjs ADDED
@@ -0,0 +1,776 @@
1
+ var __defProp = Object.defineProperty;
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/app/index.ts
31
+ import "./globals.css";
32
+
33
+ // src/app/NextAppRouterUtils.ts
34
+ import { cache } from "react";
35
+ import { notFound } from "next/navigation";
36
+
37
+ // src/app/BaseUtils.ts
38
+ async function exchangeToken(config) {
39
+ try {
40
+ const response = await fetch(`${config.apiUrl}/exchange-token`, {
41
+ method: "POST",
42
+ headers: {
43
+ "Authorization": `Bearer ${config.apiKey}`,
44
+ "x-project-id": config.projectId
45
+ }
46
+ });
47
+ if (!response.ok) {
48
+ console.error("Failed to exchange token:", response);
49
+ throw new Error("Failed to authenticate");
50
+ }
51
+ const data = await response.json();
52
+ return data.token;
53
+ } catch (error) {
54
+ console.error("Failed to exchange token:", error);
55
+ return null;
56
+ }
57
+ }
58
+
59
+ // src/app/lib/utils.ts
60
+ import { clsx } from "clsx";
61
+ import { twMerge } from "tailwind-merge";
62
+ function cn(...inputs) {
63
+ return twMerge(clsx(inputs));
64
+ }
65
+ var getFormattedDate = (date) => {
66
+ if (!date) return "";
67
+ return new Date(date).toISOString().split("T")[0];
68
+ };
69
+ var getVisiblePages = (current, total) => {
70
+ if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1);
71
+ if (current <= 3) return [1, 2, 3, 4, 5, null, total];
72
+ if (current >= total - 2) return [1, null, total - 4, total - 3, total - 2, total - 1, total];
73
+ return [1, null, current - 1, current, current + 1, null, total];
74
+ };
75
+
76
+ // src/app/NextAppRouterUtils.ts
77
+ var getAuthToken = cache(async (config) => {
78
+ return exchangeToken(config);
79
+ });
80
+ async function getBlogPosts(config, params = {}) {
81
+ const token = await getAuthToken(config);
82
+ const queryString = new URLSearchParams(
83
+ Object.entries(params).map(([key, value]) => [key, String(value)])
84
+ ).toString();
85
+ const url = `${config.apiUrl}/sdk/blogs${queryString ? `?${queryString}` : ""}`;
86
+ const response = await fetch(url, {
87
+ headers: {
88
+ "Authorization": `Bearer ${token}`,
89
+ "x-project-id": config.projectId
90
+ },
91
+ next: { revalidate: 3600 }
92
+ });
93
+ if (!response.ok) {
94
+ console.error("Failed to fetch blog posts:", response);
95
+ throw new Error(`Failed to fetch blog posts: ${response.status} ${response.statusText}`);
96
+ }
97
+ const data = await response.json();
98
+ return data;
99
+ }
100
+ async function getBlogPost(config, slug) {
101
+ const token = await getAuthToken(config);
102
+ const response = await fetch(`${config.apiUrl}/sdk/blogs/${slug}`, {
103
+ headers: {
104
+ "Authorization": `Bearer ${token}`,
105
+ "x-project-id": config.projectId
106
+ },
107
+ next: { revalidate: 3600 }
108
+ });
109
+ if (!response.ok) {
110
+ throw new Error(`Failed to fetch blog post: ${response.status} ${response.statusText}`);
111
+ }
112
+ return response.json();
113
+ }
114
+ async function getBlogPaths(config) {
115
+ const { blogs } = await getBlogPosts(config, { index: 0, limit: 1e4 });
116
+ return blogs.map((blog) => ({ slug: blog.slug }));
117
+ }
118
+ async function generateMetadata(config, slug) {
119
+ var _a, _b;
120
+ if (slug) {
121
+ const post = await getBlogPost(config, slug);
122
+ if (!post) return notFound();
123
+ return {
124
+ title: post.title,
125
+ description: (_a = post.excerpt) == null ? void 0 : _a.substring(0, 160),
126
+ openGraph: {
127
+ title: post.title,
128
+ description: (_b = post.excerpt) == null ? void 0 : _b.substring(0, 160),
129
+ type: "article",
130
+ publishedTime: getFormattedDate(post.created_at),
131
+ tags: post.tags
132
+ }
133
+ };
134
+ }
135
+ return {
136
+ title: "Blog",
137
+ description: "Read our latest blog posts",
138
+ openGraph: {
139
+ title: "Blog",
140
+ description: "Read our latest blog posts",
141
+ type: "website"
142
+ }
143
+ };
144
+ }
145
+
146
+ // src/app/components/NextBlogPage.tsx
147
+ import React4 from "react";
148
+ import { notFound as notFound2 } from "next/navigation";
149
+
150
+ // src/app/components/Article.tsx
151
+ import React3 from "react";
152
+ import { lowlight as low } from "lowlight/lib/core";
153
+
154
+ // src/app/components/ui/linkBadge.tsx
155
+ import Link from "next/link";
156
+
157
+ // src/app/components/ui/badge.tsx
158
+ import * as React from "react";
159
+ import { cva } from "class-variance-authority";
160
+ var badgeVariants = cva(
161
+ "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
162
+ {
163
+ variants: {
164
+ variant: {
165
+ default: "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
166
+ secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
167
+ destructive: "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
168
+ outline: "text-foreground"
169
+ }
170
+ },
171
+ defaultVariants: {
172
+ variant: "default"
173
+ }
174
+ }
175
+ );
176
+ function Badge(_a) {
177
+ var _b = _a, { className, variant } = _b, props = __objRest(_b, ["className", "variant"]);
178
+ return /* @__PURE__ */ React.createElement("div", __spreadValues({ className: cn(badgeVariants({ variant }), className) }, props));
179
+ }
180
+
181
+ // src/app/components/ui/linkBadge.tsx
182
+ import React2 from "react";
183
+ var LinkBadge = ({ children, href }) => {
184
+ return /* @__PURE__ */ React2.createElement(Link, { href }, /* @__PURE__ */ React2.createElement(Badge, { variant: "outline", className: "text-xs hover:cursor-pointer hover:bg-primary hover:text-primary-foreground" }, children));
185
+ };
186
+
187
+ // src/app/components/Article.tsx
188
+ import javascript from "highlight.js/lib/languages/javascript";
189
+ import typescript from "highlight.js/lib/languages/typescript";
190
+ import css from "highlight.js/lib/languages/css";
191
+ import html from "highlight.js/lib/languages/xml";
192
+ var Article = ({ post, content, style }) => {
193
+ low.registerLanguage("css", css);
194
+ low.registerLanguage("js", javascript);
195
+ low.registerLanguage("ts", typescript);
196
+ low.registerLanguage("html", html);
197
+ const contentHtml = {
198
+ __html: content
199
+ };
200
+ return post && /* @__PURE__ */ React3.createElement("article", { style, className: "easyblog" }, post.thumbnail && /* @__PURE__ */ React3.createElement("img", { src: post.thumbnail, alt: post.title, className: "w-full h-64 object-cover mb-8 rounded-lg" }), /* @__PURE__ */ React3.createElement("header", null, /* @__PURE__ */ React3.createElement("h1", { className: "title" }, post.title), /* @__PURE__ */ React3.createElement("div", { className: "info" }, /* @__PURE__ */ React3.createElement("div", { className: "author" }, "Created by ", /* @__PURE__ */ React3.createElement("span", { className: "font-semibold" }, post.author)), /* @__PURE__ */ React3.createElement("div", { className: "date" }, "Published at ", /* @__PURE__ */ React3.createElement("span", { className: "font-semibold" }, getFormattedDate(post.created_at))))), /* @__PURE__ */ React3.createElement("div", { className: "content", dangerouslySetInnerHTML: contentHtml }), /* @__PURE__ */ React3.createElement("footer", { className: "mt-8 pt-4 border-t border-gray-200" }, post.tags && post.tags.length > 0 && /* @__PURE__ */ React3.createElement("div", { className: "flex flex-wrap gap-2 my-4" }, /* @__PURE__ */ React3.createElement("span", { className: "text-sm font-semibold " }, "Tags"), /* @__PURE__ */ React3.createElement("div", { className: "flex flex-wrap gap-2" }, post.tags.map((tag, index) => /* @__PURE__ */ React3.createElement(LinkBadge, { href: `/blogs?tags=${tag}`, key: index }, tag)))), post.category && /* @__PURE__ */ React3.createElement("div", { className: "flex flex-wrap gap-2 my-4" }, /* @__PURE__ */ React3.createElement("span", { className: "text-sm font-semibold" }, "Category"), /* @__PURE__ */ React3.createElement(LinkBadge, { href: `/blogs?category=${post.category}` }, post.category))));
201
+ };
202
+
203
+ // src/app/components/NextBlogPage.tsx
204
+ async function NextBlogPage(props) {
205
+ try {
206
+ const response = await getBlogPost({
207
+ apiKey: props.config.apiKey,
208
+ projectId: props.config.projectId,
209
+ apiUrl: props.config.apiUrl
210
+ }, props.slug);
211
+ if (!response.blog) return notFound2();
212
+ const post = response.blog;
213
+ const htmlContent = response.html_content;
214
+ return /* @__PURE__ */ React4.createElement(
215
+ Article,
216
+ {
217
+ post,
218
+ content: htmlContent,
219
+ style: props.style
220
+ }
221
+ );
222
+ } catch (error) {
223
+ console.error("Error fetching blog post:", error);
224
+ return notFound2();
225
+ }
226
+ }
227
+
228
+ // src/app/components/NextBlogListPage.tsx
229
+ import React10 from "react";
230
+
231
+ // src/app/components/ArticleGroup.tsx
232
+ import React7 from "react";
233
+
234
+ // src/app/components/ArticleCard.tsx
235
+ import React6 from "react";
236
+
237
+ // src/app/components/ui/card.tsx
238
+ import * as React5 from "react";
239
+ var Card = React5.forwardRef((_a, ref) => {
240
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
241
+ return /* @__PURE__ */ React5.createElement(
242
+ "div",
243
+ __spreadValues({
244
+ ref,
245
+ className: cn(
246
+ "rounded-xl border bg-card text-card-foreground shadow",
247
+ className
248
+ )
249
+ }, props)
250
+ );
251
+ });
252
+ Card.displayName = "Card";
253
+ var CardHeader = React5.forwardRef((_a, ref) => {
254
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
255
+ return /* @__PURE__ */ React5.createElement(
256
+ "div",
257
+ __spreadValues({
258
+ ref,
259
+ className: cn("flex flex-col space-y-1.5 p-6", className)
260
+ }, props)
261
+ );
262
+ });
263
+ CardHeader.displayName = "CardHeader";
264
+ var CardTitle = React5.forwardRef((_a, ref) => {
265
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
266
+ return /* @__PURE__ */ React5.createElement(
267
+ "div",
268
+ __spreadValues({
269
+ ref,
270
+ className: cn("font-semibold leading-none tracking-tight", className)
271
+ }, props)
272
+ );
273
+ });
274
+ CardTitle.displayName = "CardTitle";
275
+ var CardDescription = React5.forwardRef((_a, ref) => {
276
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
277
+ return /* @__PURE__ */ React5.createElement(
278
+ "div",
279
+ __spreadValues({
280
+ ref,
281
+ className: cn("text-sm text-muted-foreground", className)
282
+ }, props)
283
+ );
284
+ });
285
+ CardDescription.displayName = "CardDescription";
286
+ var CardContent = React5.forwardRef((_a, ref) => {
287
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
288
+ return /* @__PURE__ */ React5.createElement("div", __spreadValues({ ref, className: cn("p-6 pt-0", className) }, props));
289
+ });
290
+ CardContent.displayName = "CardContent";
291
+ var CardFooter = React5.forwardRef((_a, ref) => {
292
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
293
+ return /* @__PURE__ */ React5.createElement(
294
+ "div",
295
+ __spreadValues({
296
+ ref,
297
+ className: cn("flex items-center p-6 pt-0", className)
298
+ }, props)
299
+ );
300
+ });
301
+ CardFooter.displayName = "CardFooter";
302
+
303
+ // src/app/components/ArticleCard.tsx
304
+ import Link2 from "next/link.js";
305
+ var ArticleCard = ({
306
+ blog,
307
+ showThumbnail = true,
308
+ showReadingTime = true,
309
+ showExcerpt = true,
310
+ showTags = true,
311
+ showDate = true,
312
+ horizontal = false,
313
+ showAuthor = true,
314
+ showCategory = true,
315
+ isNextPage = false
316
+ }) => {
317
+ const renderTags = (tags) => {
318
+ return tags.map((tag, index) => {
319
+ return isNextPage ? /* @__PURE__ */ React6.createElement(LinkBadge, { key: index, href: `/blogs/?tags=${tag}` }, tag) : /* @__PURE__ */ React6.createElement(Badge, { key: index, variant: "outline", className: "text-xs rounded-full hover:cursor-pointer hover:bg-primary hover:text-primary-foreground" }, tag);
320
+ });
321
+ };
322
+ const renderCategory = () => {
323
+ return isNextPage ? /* @__PURE__ */ React6.createElement(Link2, { href: `/blogs/?category=${blog.category}`, className: "hover:underline" }, " | ", blog.category) : /* @__PURE__ */ React6.createElement("span", null, " | ", blog.category);
324
+ };
325
+ const renderThumbnail = () => {
326
+ return isNextPage ? /* @__PURE__ */ React6.createElement(Link2, { href: `/blogs/${blog.slug}` }, /* @__PURE__ */ React6.createElement("img", { className: `${horizontal ? "w-48 h-full" : "w-full h-48"} object-cover`, src: blog.thumbnail, alt: blog.title })) : /* @__PURE__ */ React6.createElement("img", { className: `${horizontal ? "w-48 h-full" : "w-full h-48"} object-cover`, src: blog.thumbnail, alt: blog.title });
327
+ };
328
+ const renderTitle = () => {
329
+ return isNextPage ? /* @__PURE__ */ React6.createElement(Link2, { href: `/blogs/${blog.slug}`, className: "hover:underline text-primary" }, blog.title) : /* @__PURE__ */ React6.createElement("h3", { className: "font-bold text-xl mb-2 text-wrap" }, blog.title);
330
+ };
331
+ return /* @__PURE__ */ React6.createElement(Card, { className: `max-w-full overflow-hidden ${horizontal ? "flex flex-row" : ""}` }, blog.thumbnail && showThumbnail && /* @__PURE__ */ React6.createElement(CardHeader, { className: "p-0" }, renderThumbnail()), /* @__PURE__ */ React6.createElement(CardContent, { className: "p-6" }, renderTitle(), (showAuthor || showDate || showCategory) && /* @__PURE__ */ React6.createElement("p", { className: "text-muted-foreground" }, showAuthor && /* @__PURE__ */ React6.createElement("span", null, blog.author), " ", showDate && /* @__PURE__ */ React6.createElement("span", null, "| ", getFormattedDate(blog.created_at)), " ", blog.category && showCategory && renderCategory()), blog.reading_time && showReadingTime && /* @__PURE__ */ React6.createElement("p", { className: "text-muted-foreground text-sm mt-2" }, blog.reading_time, " minutes to read"), showExcerpt && /* @__PURE__ */ React6.createElement("p", { className: "text-muted-foreground text-sm mt-2" }, blog.excerpt), horizontal && /* @__PURE__ */ React6.createElement("div", { className: "mt-4 flex flex-wrap gap-2 items-start" }, showTags && blog.tags.map((tag, index) => /* @__PURE__ */ React6.createElement(LinkBadge, { key: index, href: `/blogs?tags=${tag}` }, tag)))), !horizontal && /* @__PURE__ */ React6.createElement(CardFooter, { className: "flex flex-wrap gap-2 items-start" }, showTags && renderTags(blog.tags)));
332
+ };
333
+
334
+ // src/app/components/ArticleGroup.tsx
335
+ var ArticleGroup = ({
336
+ type,
337
+ blogs,
338
+ showThumbnail = true,
339
+ showReadingTime = true,
340
+ showExcerpt = true,
341
+ showTags = true,
342
+ showDate = true,
343
+ showAuthor = true,
344
+ showCategory = true,
345
+ isNextPage = false
346
+ }) => {
347
+ if (!blogs || blogs.length === 0) {
348
+ return /* @__PURE__ */ React7.createElement("div", null, "No blogs found. Please refresh the page.");
349
+ }
350
+ const renderGridView = () => {
351
+ return /* @__PURE__ */ React7.createElement("div", { className: "grid grid-cols-1 md:grid-cols-3 lg:grid-cols-3 gap-6" }, blogs.map((blog) => /* @__PURE__ */ React7.createElement(
352
+ ArticleCard,
353
+ {
354
+ key: blog._id,
355
+ blog,
356
+ showThumbnail,
357
+ showReadingTime,
358
+ showExcerpt,
359
+ showTags,
360
+ showDate,
361
+ showAuthor,
362
+ showCategory,
363
+ isNextPage
364
+ }
365
+ )));
366
+ };
367
+ const renderListView = () => {
368
+ return /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col gap-4 min-w-[800px]" }, blogs.map((blog) => /* @__PURE__ */ React7.createElement(
369
+ ArticleCard,
370
+ {
371
+ key: blog._id,
372
+ blog,
373
+ showThumbnail,
374
+ showReadingTime,
375
+ showExcerpt,
376
+ showTags,
377
+ showDate,
378
+ showAuthor,
379
+ showCategory,
380
+ horizontal: true,
381
+ isNextPage
382
+ }
383
+ )));
384
+ };
385
+ return /* @__PURE__ */ React7.createElement("div", null, type === "grid" ? renderGridView() : renderListView());
386
+ };
387
+
388
+ // src/app/components/ui/pagination.tsx
389
+ import * as React9 from "react";
390
+ import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react";
391
+
392
+ // src/app/components/ui/button.tsx
393
+ import * as React8 from "react";
394
+ import { Slot } from "@radix-ui/react-slot";
395
+ import { cva as cva2 } from "class-variance-authority";
396
+ var buttonVariants = cva2(
397
+ "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",
398
+ {
399
+ variants: {
400
+ variant: {
401
+ default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
402
+ destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
403
+ outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
404
+ secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
405
+ ghost: "hover:bg-accent hover:text-accent-foreground",
406
+ link: "text-primary underline-offset-4 hover:underline"
407
+ },
408
+ size: {
409
+ default: "h-9 px-4 py-2",
410
+ sm: "h-8 rounded-md px-3 text-xs",
411
+ lg: "h-10 rounded-md px-8",
412
+ icon: "h-9 w-9"
413
+ }
414
+ },
415
+ defaultVariants: {
416
+ variant: "default",
417
+ size: "default"
418
+ }
419
+ }
420
+ );
421
+ var Button = React8.forwardRef(
422
+ (_a, ref) => {
423
+ var _b = _a, { className, variant, size, asChild = false } = _b, props = __objRest(_b, ["className", "variant", "size", "asChild"]);
424
+ const Comp = asChild ? Slot : "button";
425
+ return /* @__PURE__ */ React8.createElement(
426
+ Comp,
427
+ __spreadValues({
428
+ className: cn(buttonVariants({ variant, size, className })),
429
+ ref
430
+ }, props)
431
+ );
432
+ }
433
+ );
434
+ Button.displayName = "Button";
435
+
436
+ // src/app/components/ui/pagination.tsx
437
+ import Link3 from "next/link";
438
+ var Pagination = (_a) => {
439
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
440
+ return /* @__PURE__ */ React9.createElement(
441
+ "nav",
442
+ __spreadValues({
443
+ role: "navigation",
444
+ "aria-label": "pagination",
445
+ className: cn("mx-auto flex w-full justify-center", className)
446
+ }, props)
447
+ );
448
+ };
449
+ Pagination.displayName = "Pagination";
450
+ var PaginationContent = React9.forwardRef((_a, ref) => {
451
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
452
+ return /* @__PURE__ */ React9.createElement(
453
+ "ul",
454
+ __spreadValues({
455
+ ref,
456
+ className: cn("flex flex-row items-center gap-1", className)
457
+ }, props)
458
+ );
459
+ });
460
+ PaginationContent.displayName = "PaginationContent";
461
+ var PaginationItem = React9.forwardRef((_a, ref) => {
462
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
463
+ return /* @__PURE__ */ React9.createElement("li", __spreadValues({ ref, className: cn("", className) }, props));
464
+ });
465
+ PaginationItem.displayName = "PaginationItem";
466
+ var PaginationLink = (_a) => {
467
+ var _b = _a, {
468
+ className,
469
+ isActive,
470
+ size = "icon"
471
+ } = _b, props = __objRest(_b, [
472
+ "className",
473
+ "isActive",
474
+ "size"
475
+ ]);
476
+ return /* @__PURE__ */ React9.createElement(
477
+ Link3,
478
+ __spreadValues({
479
+ "aria-current": isActive ? "page" : void 0,
480
+ className: cn(
481
+ buttonVariants({
482
+ variant: isActive ? "outline" : "ghost",
483
+ size
484
+ }),
485
+ className
486
+ )
487
+ }, props)
488
+ );
489
+ };
490
+ PaginationLink.displayName = "PaginationLink";
491
+ var PaginationPrevious = (_a) => {
492
+ var _b = _a, {
493
+ className
494
+ } = _b, props = __objRest(_b, [
495
+ "className"
496
+ ]);
497
+ return /* @__PURE__ */ React9.createElement(
498
+ PaginationLink,
499
+ __spreadValues({
500
+ "aria-label": "Go to previous page",
501
+ size: "default",
502
+ className: cn("gap-1 pl-2.5", className)
503
+ }, props),
504
+ /* @__PURE__ */ React9.createElement(ChevronLeft, { className: "h-4 w-4" }),
505
+ /* @__PURE__ */ React9.createElement("span", null, "Previous")
506
+ );
507
+ };
508
+ PaginationPrevious.displayName = "PaginationPrevious";
509
+ var PaginationNext = (_a) => {
510
+ var _b = _a, {
511
+ className
512
+ } = _b, props = __objRest(_b, [
513
+ "className"
514
+ ]);
515
+ return /* @__PURE__ */ React9.createElement(
516
+ PaginationLink,
517
+ __spreadValues({
518
+ "aria-label": "Go to next page",
519
+ size: "default",
520
+ className: cn("gap-1 pr-2.5", className)
521
+ }, props),
522
+ /* @__PURE__ */ React9.createElement("span", null, "Next"),
523
+ /* @__PURE__ */ React9.createElement(ChevronRight, { className: "h-4 w-4" })
524
+ );
525
+ };
526
+ PaginationNext.displayName = "PaginationNext";
527
+ var PaginationEllipsis = (_a) => {
528
+ var _b = _a, {
529
+ className
530
+ } = _b, props = __objRest(_b, [
531
+ "className"
532
+ ]);
533
+ return /* @__PURE__ */ React9.createElement(
534
+ "span",
535
+ __spreadValues({
536
+ "aria-hidden": true,
537
+ className: cn("flex h-9 w-9 items-center justify-center", className)
538
+ }, props),
539
+ /* @__PURE__ */ React9.createElement(MoreHorizontal, { className: "h-4 w-4" }),
540
+ /* @__PURE__ */ React9.createElement("span", { className: "sr-only" }, "More pages")
541
+ );
542
+ };
543
+ PaginationEllipsis.displayName = "PaginationEllipsis";
544
+
545
+ // src/app/components/NextBlogListPage.tsx
546
+ var DEFAULT_BLOG_PER_PAGE = 9;
547
+ async function NextBlogListPage(props) {
548
+ var _a, _b;
549
+ const postsPerPage = ((_a = props.displayOptions) == null ? void 0 : _a.blogPerPage) || DEFAULT_BLOG_PER_PAGE;
550
+ const searchParams = props.searchParams || {};
551
+ const currentPage = Number(searchParams.page) || 1;
552
+ const queryParams = {
553
+ index: (currentPage - 1) * postsPerPage,
554
+ limit: postsPerPage,
555
+ category: searchParams.category || "",
556
+ tags: ((_b = searchParams.tags) == null ? void 0 : _b.split(",")) || []
557
+ };
558
+ const res = await getBlogPosts(
559
+ props.config,
560
+ queryParams
561
+ );
562
+ const { blogs, total } = res;
563
+ const totalPages = Math.ceil(total / queryParams.limit);
564
+ const visiblePages = getVisiblePages(currentPage, totalPages);
565
+ return /* @__PURE__ */ React10.createElement("div", null, /* @__PURE__ */ React10.createElement(
566
+ ArticleGroup,
567
+ __spreadValues({
568
+ blogs,
569
+ type: props.type
570
+ }, props.displayOptions)
571
+ ), totalPages > 1 && /* @__PURE__ */ React10.createElement(Pagination, { className: "mt-8" }, /* @__PURE__ */ React10.createElement(PaginationContent, null, currentPage > 1 && /* @__PURE__ */ React10.createElement(PaginationItem, null, /* @__PURE__ */ React10.createElement(PaginationPrevious, { href: `/blogs?page=${currentPage - 1}` })), visiblePages.map((pageNum, idx) => pageNum === null ? /* @__PURE__ */ React10.createElement(PaginationItem, { key: `ellipsis-${idx}` }, /* @__PURE__ */ React10.createElement(PaginationEllipsis, null)) : /* @__PURE__ */ React10.createElement(PaginationItem, { key: pageNum }, /* @__PURE__ */ React10.createElement(
572
+ PaginationLink,
573
+ {
574
+ href: `/blogs?page=${pageNum}`,
575
+ isActive: pageNum === currentPage
576
+ },
577
+ pageNum
578
+ ))), currentPage < totalPages && /* @__PURE__ */ React10.createElement(PaginationItem, null, /* @__PURE__ */ React10.createElement(PaginationNext, { href: `/blogs?page=${currentPage + 1}` })))));
579
+ }
580
+
581
+ // src/app/NextPageRouterUtils.ts
582
+ var tokenCache = {};
583
+ var CACHE_DURATION = 36e5;
584
+ async function getAuthToken2(config) {
585
+ const cacheKey = `${config.projectId}-${config.apiKey}`;
586
+ const now = Date.now();
587
+ if (tokenCache[cacheKey] && tokenCache[cacheKey].expires > now) {
588
+ return tokenCache[cacheKey].token;
589
+ }
590
+ const token = await exchangeToken(config);
591
+ tokenCache[cacheKey] = {
592
+ token,
593
+ expires: now + CACHE_DURATION
594
+ };
595
+ return token;
596
+ }
597
+ async function getBlogPostsPageRouter(config, params = {}) {
598
+ const token = await getAuthToken2(config);
599
+ const queryString = new URLSearchParams(
600
+ Object.entries(params).map(([key, value]) => [key, String(value)])
601
+ ).toString();
602
+ const url = `${config.apiUrl}/sdk/blogs${queryString ? `?${queryString}` : ""}`;
603
+ const response = await fetch(url, {
604
+ headers: {
605
+ "Authorization": `Bearer ${token}`,
606
+ "x-project-id": config.projectId
607
+ }
608
+ });
609
+ if (!response.ok) {
610
+ console.error("Failed to fetch blog posts:", response);
611
+ throw new Error(`Failed to fetch blog posts: ${response.status} ${response.statusText}`);
612
+ }
613
+ const data = await response.json();
614
+ return data;
615
+ }
616
+ async function getBlogPostPageRouter(config, slug) {
617
+ const token = await getAuthToken2(config);
618
+ const response = await fetch(`${config.apiUrl}/sdk/blogs/${slug}`, {
619
+ headers: {
620
+ "Authorization": `Bearer ${token}`,
621
+ "x-project-id": config.projectId
622
+ }
623
+ });
624
+ if (!response.ok) {
625
+ const errorMessage = `Failed to fetch blog post: ${response.status} ${response.statusText}`;
626
+ throw new Error(errorMessage);
627
+ }
628
+ return response.json();
629
+ }
630
+ async function getBlogPathsPageRouter(config) {
631
+ const { blogs } = await getBlogPostsPageRouter(config, { index: 0, limit: 1e4 });
632
+ return blogs.map((blog) => ({
633
+ params: { slug: blog.slug }
634
+ }));
635
+ }
636
+ setInterval(() => {
637
+ const now = Date.now();
638
+ Object.keys(tokenCache).forEach((key) => {
639
+ if (tokenCache[key].expires <= now) {
640
+ delete tokenCache[key];
641
+ }
642
+ });
643
+ }, CACHE_DURATION);
644
+
645
+ // src/app/components/NextBlogListPageForPageRouter.tsx
646
+ import React11 from "react";
647
+ var DEFAULT_BLOG_PER_PAGE2 = 9;
648
+ function NextBlogListPageForPageRouter(props) {
649
+ if (!props.blogs) {
650
+ return null;
651
+ }
652
+ const visiblePages = getVisiblePages(props.currentPage, props.totalPages);
653
+ return /* @__PURE__ */ React11.createElement("div", null, /* @__PURE__ */ React11.createElement(
654
+ ArticleGroup,
655
+ __spreadValues({
656
+ blogs: props.blogs,
657
+ type: props.type
658
+ }, props.displayOptions)
659
+ ), props.totalPages > 1 && /* @__PURE__ */ React11.createElement(Pagination, { className: "mt-8" }, /* @__PURE__ */ React11.createElement(PaginationContent, null, props.currentPage > 1 && /* @__PURE__ */ React11.createElement(PaginationItem, null, /* @__PURE__ */ React11.createElement(PaginationPrevious, { href: `/blogs?page=${props.currentPage - 1}` })), visiblePages.map((pageNum, idx) => pageNum === null ? /* @__PURE__ */ React11.createElement(PaginationItem, { key: `ellipsis-${idx}` }, /* @__PURE__ */ React11.createElement(PaginationEllipsis, null)) : /* @__PURE__ */ React11.createElement(PaginationItem, { key: pageNum }, /* @__PURE__ */ React11.createElement(
660
+ PaginationLink,
661
+ {
662
+ href: `/blogs?page=${pageNum}`,
663
+ isActive: pageNum === props.currentPage
664
+ },
665
+ pageNum
666
+ ))), props.currentPage < props.totalPages && /* @__PURE__ */ React11.createElement(PaginationItem, null, /* @__PURE__ */ React11.createElement(PaginationNext, { href: `/blogs?page=${props.currentPage + 1}` })))));
667
+ }
668
+ function withServerSideProps(pageConfig) {
669
+ return {
670
+ async getServerSideProps({ query }) {
671
+ var _a;
672
+ try {
673
+ const currentPage = query.page ? parseInt(query.page) : 1;
674
+ const postsPerPage = ((_a = pageConfig.displayOptions) == null ? void 0 : _a.blogPerPage) || DEFAULT_BLOG_PER_PAGE2;
675
+ const { blogs, total } = await getBlogPostsPageRouter(pageConfig.config, {
676
+ index: (currentPage - 1) * postsPerPage,
677
+ limit: postsPerPage,
678
+ category: query.category,
679
+ tags: query.tags ? query.tags.split(",") : void 0
680
+ });
681
+ const totalPages = Math.ceil(total / postsPerPage);
682
+ return {
683
+ props: {
684
+ blogs,
685
+ type: pageConfig.type,
686
+ displayOptions: pageConfig.displayOptions || {},
687
+ currentPage,
688
+ totalPages
689
+ }
690
+ };
691
+ } catch (error) {
692
+ console.error("Error fetching blog posts:", error);
693
+ return {
694
+ notFound: true
695
+ };
696
+ }
697
+ }
698
+ };
699
+ }
700
+
701
+ // src/app/components/NextBlogPageForPageRouter.tsx
702
+ import React12 from "react";
703
+ function NextBlogPageForPageRouter(props) {
704
+ if (!props.post) {
705
+ return null;
706
+ }
707
+ return /* @__PURE__ */ React12.createElement(
708
+ Article,
709
+ {
710
+ post: props.post,
711
+ content: props.htmlContent,
712
+ style: props.style
713
+ }
714
+ );
715
+ }
716
+ function withStaticProps(pageConfig) {
717
+ return {
718
+ async getStaticProps({ params }) {
719
+ try {
720
+ const response = await getBlogPostPageRouter({
721
+ apiKey: pageConfig.config.apiKey,
722
+ projectId: pageConfig.config.projectId,
723
+ apiUrl: pageConfig.config.apiUrl
724
+ }, params.slug);
725
+ if (!response.blog) {
726
+ return {
727
+ notFound: true
728
+ };
729
+ }
730
+ return {
731
+ props: {
732
+ post: response.blog,
733
+ htmlContent: response.html_content
734
+ },
735
+ revalidate: 60
736
+ };
737
+ } catch (error) {
738
+ console.error("Error fetching blog post:", error);
739
+ return {
740
+ notFound: true
741
+ };
742
+ }
743
+ },
744
+ async getStaticPaths() {
745
+ try {
746
+ const paths = await getBlogPathsPageRouter(pageConfig.config);
747
+ return {
748
+ paths,
749
+ fallback: "blocking"
750
+ };
751
+ } catch (error) {
752
+ console.error("Error fetching blog slugs:", error);
753
+ return {
754
+ paths: [],
755
+ fallback: "blocking"
756
+ };
757
+ }
758
+ }
759
+ };
760
+ }
761
+ export {
762
+ NextBlogListPage,
763
+ NextBlogListPageForPageRouter,
764
+ NextBlogPage,
765
+ NextBlogPageForPageRouter,
766
+ generateMetadata,
767
+ getBlogPaths,
768
+ getBlogPathsPageRouter,
769
+ getBlogPost,
770
+ getBlogPostPageRouter,
771
+ getBlogPosts,
772
+ getBlogPostsPageRouter,
773
+ withServerSideProps as withListServerSideProps,
774
+ withStaticProps as withPageStaticProps
775
+ };
776
+ //# sourceMappingURL=index.mjs.map