@arch-cadre/blog-module 1.0.7 → 1.0.8
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/actions/index.d.ts +38 -5
- package/dist/actions/index.js +149 -0
- package/dist/components/BlogStatsWidget.d.ts +1 -2
- package/dist/components/BlogStatsWidget.js +17 -0
- package/dist/components/RecentCommentsWidget.d.ts +1 -2
- package/dist/components/RecentCommentsWidget.js +24 -0
- package/dist/components/RecentPostsWidget.d.ts +1 -2
- package/dist/components/RecentPostsWidget.js +24 -0
- package/dist/components/ui/button.d.ts +1 -1
- package/dist/components/ui/button.js +33 -0
- package/dist/components/ui/card.js +12 -0
- package/dist/components/ui/input.js +8 -0
- package/dist/components/ui/table.js +16 -0
- package/dist/components/ui/textarea.js +8 -0
- package/dist/index.js +98 -0
- package/dist/lib/{utils.mjs → utils.js} +1 -1
- package/dist/lib/validation.d.ts +2 -2
- package/dist/lib/validation.js +11 -0
- package/dist/navigation.js +21 -0
- package/dist/routes.js +55 -0
- package/dist/schema.js +60 -0
- package/dist/ui/views.d.ts +5 -6
- package/dist/ui/views.js +119 -0
- package/package.json +10 -17
- package/dist/actions/index.cjs +0 -158
- package/dist/actions/index.mjs +0 -121
- package/dist/components/BlogStatsWidget.cjs +0 -45
- package/dist/components/BlogStatsWidget.mjs +0 -13
- package/dist/components/RecentCommentsWidget.cjs +0 -47
- package/dist/components/RecentCommentsWidget.mjs +0 -28
- package/dist/components/RecentPostsWidget.cjs +0 -47
- package/dist/components/RecentPostsWidget.mjs +0 -28
- package/dist/components/ui/button.cjs +0 -53
- package/dist/components/ui/button.mjs +0 -44
- package/dist/components/ui/card.cjs +0 -46
- package/dist/components/ui/card.mjs +0 -35
- package/dist/components/ui/input.cjs +0 -23
- package/dist/components/ui/input.mjs +0 -20
- package/dist/components/ui/table.cjs +0 -66
- package/dist/components/ui/table.mjs +0 -59
- package/dist/components/ui/textarea.cjs +0 -21
- package/dist/components/ui/textarea.mjs +0 -19
- package/dist/index.cjs +0 -100
- package/dist/index.mjs +0 -95
- package/dist/intl.d.ts +0 -7
- package/dist/lib/utils.cjs +0 -11
- package/dist/lib/validation.cjs +0 -16
- package/dist/lib/validation.mjs +0 -10
- package/dist/navigation.cjs +0 -23
- package/dist/navigation.mjs +0 -21
- package/dist/routes.cjs +0 -74
- package/dist/routes.mjs +0 -68
- package/dist/schema.cjs +0 -62
- package/dist/schema.mjs +0 -53
- package/dist/styles/globals.css +0 -1
- package/dist/ui/views.cjs +0 -448
- package/dist/ui/views.mjs +0 -232
package/dist/ui/views.d.ts
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
1
|
export declare function BlogListPage({ posts }: {
|
|
3
2
|
posts?: any[];
|
|
4
|
-
}):
|
|
3
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
5
4
|
export declare function PostDetailPage({ post, comments, currentUser, }: {
|
|
6
5
|
post: any;
|
|
7
6
|
comments: any[];
|
|
8
7
|
currentUser?: any;
|
|
9
|
-
}):
|
|
8
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
10
9
|
export declare function BlogAdminPage({ posts }: {
|
|
11
10
|
posts: any[];
|
|
12
|
-
}):
|
|
13
|
-
export declare function CreatePostForm():
|
|
11
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare function CreatePostForm(): import("react/jsx-runtime").JSX.Element;
|
|
14
13
|
export declare function EditPostForm({ post }: {
|
|
15
14
|
post: any;
|
|
16
|
-
}):
|
|
15
|
+
}): import("react/jsx-runtime").JSX.Element;
|
package/dist/ui/views.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/** biome-ignore-all lint/a11y/noLabelWithoutControl: <explanation> */
|
|
2
|
+
"use client";
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { useTranslation } from "@arch-cadre/intl/client";
|
|
5
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
6
|
+
import { ArrowLeft, Eye, MessageSquare, Pencil, Plus, Trash2, User as UserIcon, } from "lucide-react";
|
|
7
|
+
import Link from "next/link";
|
|
8
|
+
import { useRouter } from "next/navigation";
|
|
9
|
+
import { useForm } from "react-hook-form";
|
|
10
|
+
import { toast } from "sonner";
|
|
11
|
+
import { createComment, createPost, deletePost, updatePost } from "../actions/index.js";
|
|
12
|
+
import { Button } from "../components/ui/button.js";
|
|
13
|
+
import { Card, CardContent, CardHeader, CardTitle, } from "../components/ui/card.js";
|
|
14
|
+
import { Input } from "../components/ui/input.js";
|
|
15
|
+
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "../components/ui/table.js";
|
|
16
|
+
import { Textarea } from "../components/ui/textarea.js";
|
|
17
|
+
import { commentSchema, postSchema } from "../lib/validation.js";
|
|
18
|
+
export function BlogListPage({ posts = [] }) {
|
|
19
|
+
const { t } = useTranslation();
|
|
20
|
+
return (_jsxs("div", { className: "max-w-4xl mx-auto p-6 space-y-8", children: [_jsxs("header", { className: "border-b pb-6", children: [_jsx("h1", { className: "text-4xl font-black tracking-tighter text-primary", children: t("Blog Posts") }), _jsx("p", { className: "text-muted-foreground mt-2", children: t("Reading your blog posts") })] }), _jsx("div", { className: "grid gap-6", children: posts.map((post) => (_jsx(Link, { href: `/blog/${post.slug}`, children: _jsxs(Card, { className: "group hover:shadow-lg transition-all cursor-pointer overflow-hidden border-primary/5", children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { className: "text-2xl group-hover:text-primary transition-colors", children: post.title }), _jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground mt-1", children: [_jsx(UserIcon, { className: "size-3" }), _jsx("span", { children: post.author?.name }), _jsx("span", { children: "\u2022" }), _jsx("span", { children: new Date(post.createdAt).toLocaleDateString() })] })] }), _jsx(CardContent, { children: _jsx("p", { className: "text-secondary-foreground line-clamp-2", children: post.content }) })] }) }, post.id))) })] }));
|
|
21
|
+
}
|
|
22
|
+
// --- Comment Form Component ---
|
|
23
|
+
function CommentForm({ postId }) {
|
|
24
|
+
const router = useRouter();
|
|
25
|
+
const { t } = useTranslation();
|
|
26
|
+
const { register, handleSubmit, reset, formState: { errors, isSubmitting }, } = useForm({
|
|
27
|
+
resolver: zodResolver(commentSchema.omit({ postId: true })),
|
|
28
|
+
});
|
|
29
|
+
const onSubmit = async (data) => {
|
|
30
|
+
const result = await createComment({ ...data, postId });
|
|
31
|
+
if (result.success) {
|
|
32
|
+
toast.success(t("Comment added"));
|
|
33
|
+
reset();
|
|
34
|
+
router.refresh();
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
toast.error(result.error);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
return (_jsxs("form", { onSubmit: handleSubmit(onSubmit), className: "space-y-4", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Textarea, { ...register("content"), placeholder: t("Add your comment here..."), className: errors.content ? "border-destructive" : "" }), errors.content && (_jsx("p", { className: "text-xs text-destructive", children: errors.content.message }))] }), _jsx(Button, { type: "submit", disabled: isSubmitting, size: "sm", children: isSubmitting ? t("Please wait...") : t("Create Comment") })] }));
|
|
41
|
+
}
|
|
42
|
+
// --- Detail View ---
|
|
43
|
+
export function PostDetailPage({ post, comments = [], currentUser, }) {
|
|
44
|
+
const { t } = useTranslation();
|
|
45
|
+
if (!post)
|
|
46
|
+
return _jsx("div", { className: "p-20 text-center", children: t("Post not found") });
|
|
47
|
+
return (_jsxs("div", { className: "max-w-3xl mx-auto p-6 space-y-10 pb-20", children: [_jsx(Button, { asChild: true, variant: "ghost", size: "sm", className: "gap-2", children: _jsxs(Link, { href: "/blog", children: [_jsx(ArrowLeft, { className: "size-4" }), " ", t("Back to posts")] }) }), _jsxs("article", { className: "space-y-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("h1", { className: "text-5xl font-black tracking-tighter leading-tight", children: post.title }), _jsxs("div", { className: "flex items-center gap-3 text-muted-foreground", children: [_jsx("div", { className: "size-8 rounded-full bg-primary/10 flex items-center justify-center", children: _jsx(UserIcon, { className: "size-4 text-primary" }) }), _jsxs("div", { className: "text-sm", children: [_jsx("p", { className: "font-bold text-foreground leading-none", children: post.author?.name }), _jsx("p", { className: "text-xs", children: new Date(post.createdAt).toLocaleDateString() })] })] })] }), _jsx("div", { className: "prose prose-lg dark:prose-invert max-w-none whitespace-pre-wrap pt-4 border-t", children: post.content })] }), _jsxs("section", { className: "pt-10 border-t space-y-8", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(MessageSquare, { className: "size-5" }), _jsxs("h3", { className: "text-2xl font-bold tracking-tight", children: [t("Comments"), " (", comments.length, ")"] })] }), currentUser ? (_jsxs("div", { className: "bg-muted/30 p-6 rounded-2xl border", children: [_jsx("p", { className: "text-sm font-bold mb-4", children: t("Leave a comment") }), _jsx(CommentForm, { postId: post.id })] })) : (_jsx("div", { className: "p-6 bg-amber-50 border border-amber-100 rounded-2xl text-center", children: _jsxs("p", { className: "text-sm font-medium text-amber-800", children: ["Please", " ", _jsx(Link, { href: "/signin", className: "underline font-bold", children: t("Sign in") }), " ", t("to join the conversation.")] }) })), _jsxs("div", { className: "space-y-6", children: [comments.map((comment) => (_jsxs("div", { className: "flex gap-4", children: [_jsx("div", { className: "size-10 rounded-full bg-muted flex items-center justify-center shrink-0", children: _jsx(UserIcon, { className: "size-5 opacity-40" }) }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "font-bold text-sm", children: comment.author?.name }), _jsx("span", { className: "text-[10px] opacity-50", children: new Date(comment.createdAt).toLocaleDateString() })] }), _jsx("p", { className: "text-sm text-secondary-foreground leading-relaxed", children: comment.content })] })] }, comment.id))), comments.length === 0 && (_jsx("p", { className: "text-center text-muted-foreground text-sm py-10 italic", children: t("No comments yet. Be the first to comment!") }))] })] })] }));
|
|
48
|
+
}
|
|
49
|
+
// --- Admin View Components ---
|
|
50
|
+
export function BlogAdminPage({ posts = [] }) {
|
|
51
|
+
const router = useRouter();
|
|
52
|
+
const { t } = useTranslation();
|
|
53
|
+
const handleDelete = async (id) => {
|
|
54
|
+
if (!confirm(t("Confirm deletion of this post?")))
|
|
55
|
+
return;
|
|
56
|
+
const result = await deletePost(id);
|
|
57
|
+
if (result.success) {
|
|
58
|
+
toast.success(t("Post deleted"));
|
|
59
|
+
router.refresh();
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
toast.error(t("UnexpectedError") + result.error);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
return (_jsxs("div", { className: "p-6 space-y-6", children: [_jsxs("div", { className: "flex justify-between items-center", children: [_jsx("h1", { className: "text-3xl font-black tracking-tight text-foreground", children: t("Blog posts") }), _jsx(Button, { asChild: true, size: "sm", className: "gap-2", children: _jsxs(Link, { href: "/kryo/blog/new", children: [_jsx(Plus, { className: "size-4" }), " ", t("New Post")] }) })] }), _jsx(Card, { className: "border-primary/10 shadow-sm overflow-hidden", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { className: "w-[40%]", children: t("Title") }), _jsx(TableHead, { children: t("Author") }), _jsx(TableHead, { children: t("Date") }), _jsx(TableHead, { className: "text-right", children: t("Actions") })] }) }), _jsxs(TableBody, { children: [posts.length === 0 && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 4, className: "h-24 text-center text-muted-foreground italic", children: t("No posts found. Create your first post!") }) })), posts.map((post) => (_jsxs(TableRow, { className: "transition-colors", children: [_jsx(TableCell, { className: "font-bold", children: post.title }), _jsx(TableCell, { className: "text-xs", children: post.author?.name }), _jsx(TableCell, { className: "text-muted-foreground text-xs", children: new Date(post.createdAt).toLocaleDateString() }), _jsx(TableCell, { className: "text-right", children: _jsxs("div", { className: "flex justify-end gap-2", children: [_jsx(Button, { asChild: true, variant: "ghost", size: "icon", className: "size-8", children: _jsx(Link, { href: `/blog/${post.slug}`, target: "_blank", children: _jsx(Eye, { className: "size-4" }) }) }), _jsx(Button, { asChild: true, variant: "ghost", size: "icon", className: "size-8", children: _jsx(Link, { href: `/kryo/blog/edit/${post.id}`, children: _jsx(Pencil, { className: "size-4" }) }) }), _jsx(Button, { variant: "ghost", size: "icon", className: "size-8 text-destructive hover:text-destructive hover:bg-destructive/10", onClick: () => handleDelete(post.id), children: _jsx(Trash2, { className: "size-4" }) })] }) })] }, post.id)))] })] }) })] }));
|
|
66
|
+
}
|
|
67
|
+
export function CreatePostForm() {
|
|
68
|
+
const router = useRouter();
|
|
69
|
+
const { t } = useTranslation();
|
|
70
|
+
const { register, handleSubmit, formState: { errors, isSubmitting }, } = useForm({
|
|
71
|
+
resolver: zodResolver(postSchema.omit({ slug: true })),
|
|
72
|
+
});
|
|
73
|
+
const onSubmit = async (data) => {
|
|
74
|
+
const slug = data.title
|
|
75
|
+
.toLowerCase()
|
|
76
|
+
.replace(/ /g, "-")
|
|
77
|
+
.replace(/[^\w-]+/g, "");
|
|
78
|
+
const result = await createPost({ ...data, slug });
|
|
79
|
+
if (result.success) {
|
|
80
|
+
toast.success(t("Post created"));
|
|
81
|
+
router.push("/kryo/blog");
|
|
82
|
+
router.refresh();
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
toast.error(t("UnexpectedError") + result.error);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
return (_jsxs("div", { className: "max-w-2xl mx-auto p-6 space-y-6", children: [_jsxs("div", { className: "flex items-center gap-4", children: [_jsx(Button, { asChild: true, variant: "outline", size: "icon", className: "rounded-lg", children: _jsx(Link, { href: "/kryo/blog", children: _jsx(ArrowLeft, { className: "size-4" }) }) }), _jsx("h1", { className: "text-2xl font-black text-foreground", children: t("New Post") })] }), _jsx(Card, { className: "border-primary/10 shadow-lg", children: _jsx(CardContent, { className: "pt-6", children: _jsxs("form", { onSubmit: handleSubmit(onSubmit), className: "space-y-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-black uppercase tracking-widest opacity-50 px-1", children: t("Title") }), _jsx(Input, { ...register("title"), className: errors.title ? "border-destructive font-bold" : "font-bold", placeholder: t("Title of your post") }), errors.title && (_jsx("p", { className: "text-xs text-destructive font-bold", children: errors.title.message }))] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-black uppercase tracking-widest opacity-50 px-1", children: t("Content") }), _jsx(Textarea, { ...register("content"), rows: 12, className: errors.content
|
|
89
|
+
? "border-destructive resize-none"
|
|
90
|
+
: "resize-none", placeholder: t("Content of your post") }), errors.content && (_jsx("p", { className: "text-xs text-destructive font-bold", children: errors.content.message }))] }), _jsx(Button, { type: "submit", disabled: isSubmitting, className: "w-full text-sm uppercase tracking-widest transition-all", children: isSubmitting ? t("Please wait...") : t("Publish") })] }) }) })] }));
|
|
91
|
+
}
|
|
92
|
+
export function EditPostForm({ post }) {
|
|
93
|
+
const router = useRouter();
|
|
94
|
+
const { t } = useTranslation();
|
|
95
|
+
const { register, handleSubmit, formState: { errors, isSubmitting }, } = useForm({
|
|
96
|
+
resolver: zodResolver(postSchema),
|
|
97
|
+
defaultValues: {
|
|
98
|
+
title: post.title,
|
|
99
|
+
content: post.content,
|
|
100
|
+
slug: post.slug,
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
const onSubmit = async (data) => {
|
|
104
|
+
const result = await updatePost(post.id, data);
|
|
105
|
+
if (result.success) {
|
|
106
|
+
toast.success(t("Post updated"));
|
|
107
|
+
router.push("/kryo/blog");
|
|
108
|
+
router.refresh();
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
toast.error(t("UnexpectedError") + result.error);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
return (_jsxs("div", { className: "max-w-2xl mx-auto p-6 space-y-6", children: [_jsxs("div", { className: "flex items-center gap-4", children: [_jsx(Button, { asChild: true, variant: "outline", size: "icon", className: "rounded-lg", children: _jsx(Link, { href: "/kryo/blog", children: _jsx(ArrowLeft, { className: "size-4" }) }) }), _jsx("h1", { className: "text-2xl font-black text-foreground", children: t("Edit Post") })] }), _jsx(Card, { className: "border-primary/10 shadow-lg", children: _jsx(CardContent, { className: "pt-6", children: _jsxs("form", { onSubmit: handleSubmit(onSubmit), className: "space-y-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-black uppercase tracking-widest opacity-50 px-1", children: t("Title") }), _jsx(Input, { ...register("title"), className: errors.title ? "border-destructive font-bold" : "font-bold", placeholder: t("Title of your post") }), errors.title && (_jsx("p", { className: "text-xs text-destructive font-bold", children: errors.title.message }))] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-black uppercase tracking-widest opacity-50 px-1", children: t("Slug") }), _jsx(Input, { ...register("slug"), className: errors.slug
|
|
115
|
+
? "border-destructive font-mono text-sm"
|
|
116
|
+
: "font-mono text-sm", placeholder: t("Slug URL") }), errors.slug && (_jsx("p", { className: "text-xs text-destructive font-bold", children: errors.slug.message }))] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-black uppercase tracking-widest opacity-50 px-1", children: t("Content") }), _jsx(Textarea, { ...register("content"), rows: 12, className: errors.content
|
|
117
|
+
? "border-destructive resize-none"
|
|
118
|
+
: "resize-none", placeholder: t("Content of your post") }), errors.content && (_jsx("p", { className: "text-xs text-destructive font-bold", children: errors.content.message }))] }), _jsx(Button, { type: "submit", disabled: isSubmitting, className: "w-full text-sm uppercase tracking-widest transition-all", children: isSubmitting ? t("Please wait...") : t("Update") })] }) }) })] }));
|
|
119
|
+
}
|
package/package.json
CHANGED
|
@@ -1,20 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arch-cadre/blog-module",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "A sample module for Kryo framework",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
6
7
|
"exports": {
|
|
7
8
|
"./package.json": "./package.json",
|
|
8
|
-
".":
|
|
9
|
-
"types": "./dist/index.d.ts",
|
|
10
|
-
"import": "./dist/index.mjs",
|
|
11
|
-
"require": "./dist/index.cjs"
|
|
12
|
-
},
|
|
13
|
-
"./actions": {
|
|
14
|
-
"types": "./dist/actions/index.d.ts",
|
|
15
|
-
"import": "./dist/actions/index.mjs",
|
|
16
|
-
"require": "./dist/actions/index.cjs"
|
|
17
|
-
}
|
|
9
|
+
".": "./dist/index.js"
|
|
18
10
|
},
|
|
19
11
|
"files": [
|
|
20
12
|
"dist",
|
|
@@ -26,11 +18,12 @@
|
|
|
26
18
|
"clean": "rm -rf ./dist",
|
|
27
19
|
"switch:dev": "node scripts/switchToSrc.js",
|
|
28
20
|
"switch:prod": "node scripts/switchToDist.js",
|
|
29
|
-
"
|
|
30
|
-
"devs": "unbuild --stub"
|
|
21
|
+
"builds": "unbuild",
|
|
22
|
+
"devs": "unbuild --stub",
|
|
23
|
+
"build": "pnpm clean && tsc --module esnext"
|
|
31
24
|
},
|
|
32
25
|
"dependencies": {
|
|
33
|
-
"@arch-cadre/modules": "^0.0.
|
|
26
|
+
"@arch-cadre/modules": "^0.0.77",
|
|
34
27
|
"@hookform/resolvers": "^3.10.0",
|
|
35
28
|
"@radix-ui/react-slot": "^1.2.3",
|
|
36
29
|
"class-variance-authority": "^0.7.1",
|
|
@@ -53,9 +46,9 @@
|
|
|
53
46
|
"unbuild": "^3.6.1"
|
|
54
47
|
},
|
|
55
48
|
"peerDependencies": {
|
|
56
|
-
"@arch-cadre/core": "^0.0.
|
|
57
|
-
"@arch-cadre/intl": "^0.0.
|
|
58
|
-
"@arch-cadre/ui": "^0.0.
|
|
49
|
+
"@arch-cadre/core": "^0.0.51",
|
|
50
|
+
"@arch-cadre/intl": "^0.0.51",
|
|
51
|
+
"@arch-cadre/ui": "^0.0.51",
|
|
59
52
|
"react": "^19.0.0"
|
|
60
53
|
},
|
|
61
54
|
"main": "./dist/index.mjs"
|
package/dist/actions/index.cjs
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
"use server";
|
|
3
|
-
|
|
4
|
-
Object.defineProperty(exports, "__esModule", {
|
|
5
|
-
value: true
|
|
6
|
-
});
|
|
7
|
-
exports.createComment = createComment;
|
|
8
|
-
exports.createPost = createPost;
|
|
9
|
-
exports.deletePost = deletePost;
|
|
10
|
-
exports.getComments = getComments;
|
|
11
|
-
exports.getPostById = getPostById;
|
|
12
|
-
exports.getPostBySlug = getPostBySlug;
|
|
13
|
-
exports.getPosts = getPosts;
|
|
14
|
-
exports.updatePost = updatePost;
|
|
15
|
-
var _server = require("@arch-cadre/core/server");
|
|
16
|
-
var _drizzleOrm = require("drizzle-orm");
|
|
17
|
-
var _cache = require("next/cache");
|
|
18
|
-
var _validation = require("../lib/validation.cjs");
|
|
19
|
-
var _schema = require("../schema.cjs");
|
|
20
|
-
async function createPost(data) {
|
|
21
|
-
try {
|
|
22
|
-
const {
|
|
23
|
-
user
|
|
24
|
-
} = await (0, _server.getCurrentSession)();
|
|
25
|
-
if (!user) throw new Error("Unauthorized");
|
|
26
|
-
const validated = _validation.postSchema.parse(data);
|
|
27
|
-
await _server.db.insert(_schema.postsTable).values({
|
|
28
|
-
...validated,
|
|
29
|
-
authorId: user.id
|
|
30
|
-
});
|
|
31
|
-
(0, _cache.revalidatePath)("/blog");
|
|
32
|
-
return {
|
|
33
|
-
success: true
|
|
34
|
-
};
|
|
35
|
-
} catch (error) {
|
|
36
|
-
console.error("[BlogModule:Actions] createPost failed:", error);
|
|
37
|
-
return {
|
|
38
|
-
success: false,
|
|
39
|
-
error: error.message
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
async function getPosts() {
|
|
44
|
-
try {
|
|
45
|
-
return await _server.db.select({
|
|
46
|
-
id: _schema.postsTable.id,
|
|
47
|
-
title: _schema.postsTable.title,
|
|
48
|
-
slug: _schema.postsTable.slug,
|
|
49
|
-
content: _schema.postsTable.content,
|
|
50
|
-
createdAt: _schema.postsTable.createdAt,
|
|
51
|
-
author: {
|
|
52
|
-
name: _server.userTable.name
|
|
53
|
-
}
|
|
54
|
-
}).from(_schema.postsTable).innerJoin(_server.userTable, (0, _drizzleOrm.eq)(_schema.postsTable.authorId, _server.userTable.id)).orderBy((0, _drizzleOrm.desc)(_schema.postsTable.createdAt));
|
|
55
|
-
} catch (error) {
|
|
56
|
-
console.error("[BlogModule:Actions] getPosts failed:", error);
|
|
57
|
-
throw error;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
async function getPostBySlug(slug) {
|
|
61
|
-
try {
|
|
62
|
-
const [post] = await _server.db.select({
|
|
63
|
-
id: _schema.postsTable.id,
|
|
64
|
-
title: _schema.postsTable.title,
|
|
65
|
-
slug: _schema.postsTable.slug,
|
|
66
|
-
content: _schema.postsTable.content,
|
|
67
|
-
createdAt: _schema.postsTable.createdAt,
|
|
68
|
-
author: {
|
|
69
|
-
name: _server.userTable.name
|
|
70
|
-
}
|
|
71
|
-
}).from(_schema.postsTable).innerJoin(_server.userTable, (0, _drizzleOrm.eq)(_schema.postsTable.authorId, _server.userTable.id)).where((0, _drizzleOrm.eq)(_schema.postsTable.slug, slug));
|
|
72
|
-
return post || null;
|
|
73
|
-
} catch (error) {
|
|
74
|
-
console.error("[BlogModule:Actions] getPostBySlug failed:", error);
|
|
75
|
-
throw error;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
async function getPostById(id) {
|
|
79
|
-
try {
|
|
80
|
-
const [post] = await _server.db.select().from(_schema.postsTable).where((0, _drizzleOrm.eq)(_schema.postsTable.id, id));
|
|
81
|
-
return post || null;
|
|
82
|
-
} catch (error) {
|
|
83
|
-
console.error("[BlogModule:Actions] getPostById failed:", error);
|
|
84
|
-
throw error;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
async function getComments(postId) {
|
|
88
|
-
try {
|
|
89
|
-
return await _server.db.select({
|
|
90
|
-
id: _schema.commentsTable.id,
|
|
91
|
-
content: _schema.commentsTable.content,
|
|
92
|
-
createdAt: _schema.commentsTable.createdAt,
|
|
93
|
-
author: {
|
|
94
|
-
name: _server.userTable.name,
|
|
95
|
-
image: _server.userTable.image
|
|
96
|
-
}
|
|
97
|
-
}).from(_schema.commentsTable).innerJoin(_server.userTable, (0, _drizzleOrm.eq)(_schema.commentsTable.authorId, _server.userTable.id)).where((0, _drizzleOrm.eq)(_schema.commentsTable.postId, postId)).orderBy((0, _drizzleOrm.desc)(_schema.commentsTable.createdAt));
|
|
98
|
-
} catch (error) {
|
|
99
|
-
console.error("[BlogModule:Actions] getComments failed:", error);
|
|
100
|
-
throw error;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
async function createComment(data) {
|
|
104
|
-
try {
|
|
105
|
-
const {
|
|
106
|
-
user
|
|
107
|
-
} = await (0, _server.getCurrentSession)();
|
|
108
|
-
if (!user) throw new Error("Must be logged in to comment");
|
|
109
|
-
const validated = _validation.commentSchema.parse(data);
|
|
110
|
-
await _server.db.insert(_schema.commentsTable).values({
|
|
111
|
-
content: validated.content,
|
|
112
|
-
postId: validated.postId,
|
|
113
|
-
authorId: user.id
|
|
114
|
-
});
|
|
115
|
-
(0, _cache.revalidatePath)(`/blog`);
|
|
116
|
-
return {
|
|
117
|
-
success: true
|
|
118
|
-
};
|
|
119
|
-
} catch (error) {
|
|
120
|
-
console.error("[BlogModule:Actions] createComment failed:", error);
|
|
121
|
-
return {
|
|
122
|
-
success: false,
|
|
123
|
-
error: error.message
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
async function deletePost(id) {
|
|
128
|
-
try {
|
|
129
|
-
await _server.db.delete(_schema.postsTable).where((0, _drizzleOrm.eq)(_schema.postsTable.id, id));
|
|
130
|
-
(0, _cache.revalidatePath)("/blog");
|
|
131
|
-
return {
|
|
132
|
-
success: true
|
|
133
|
-
};
|
|
134
|
-
} catch (error) {
|
|
135
|
-
console.error("[BlogModule:Actions] deletePost failed:", error);
|
|
136
|
-
return {
|
|
137
|
-
success: false,
|
|
138
|
-
error: error.message
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
async function updatePost(id, data) {
|
|
143
|
-
try {
|
|
144
|
-
const validated = _validation.postSchema.parse(data);
|
|
145
|
-
await _server.db.update(_schema.postsTable).set(validated).where((0, _drizzleOrm.eq)(_schema.postsTable.id, id));
|
|
146
|
-
(0, _cache.revalidatePath)("/blog");
|
|
147
|
-
(0, _cache.revalidatePath)(`/blog/${validated.slug}`);
|
|
148
|
-
return {
|
|
149
|
-
success: true
|
|
150
|
-
};
|
|
151
|
-
} catch (error) {
|
|
152
|
-
console.error("[BlogModule:Actions] updatePost failed:", error);
|
|
153
|
-
return {
|
|
154
|
-
success: false,
|
|
155
|
-
error: error.message
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
}
|
package/dist/actions/index.mjs
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
"use server";
|
|
2
|
-
import { db, getCurrentSession, userTable } from "@arch-cadre/core/server";
|
|
3
|
-
import { desc, eq } from "drizzle-orm";
|
|
4
|
-
import { revalidatePath } from "next/cache";
|
|
5
|
-
import { commentSchema, postSchema } from "../lib/validation.mjs";
|
|
6
|
-
import { commentsTable, postsTable } from "../schema.mjs";
|
|
7
|
-
export async function createPost(data) {
|
|
8
|
-
try {
|
|
9
|
-
const { user } = await getCurrentSession();
|
|
10
|
-
if (!user) throw new Error("Unauthorized");
|
|
11
|
-
const validated = postSchema.parse(data);
|
|
12
|
-
await db.insert(postsTable).values({
|
|
13
|
-
...validated,
|
|
14
|
-
authorId: user.id
|
|
15
|
-
});
|
|
16
|
-
revalidatePath("/blog");
|
|
17
|
-
return { success: true };
|
|
18
|
-
} catch (error) {
|
|
19
|
-
console.error("[BlogModule:Actions] createPost failed:", error);
|
|
20
|
-
return { success: false, error: error.message };
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
export async function getPosts() {
|
|
24
|
-
try {
|
|
25
|
-
return await db.select({
|
|
26
|
-
id: postsTable.id,
|
|
27
|
-
title: postsTable.title,
|
|
28
|
-
slug: postsTable.slug,
|
|
29
|
-
content: postsTable.content,
|
|
30
|
-
createdAt: postsTable.createdAt,
|
|
31
|
-
author: {
|
|
32
|
-
name: userTable.name
|
|
33
|
-
}
|
|
34
|
-
}).from(postsTable).innerJoin(userTable, eq(postsTable.authorId, userTable.id)).orderBy(desc(postsTable.createdAt));
|
|
35
|
-
} catch (error) {
|
|
36
|
-
console.error("[BlogModule:Actions] getPosts failed:", error);
|
|
37
|
-
throw error;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
export async function getPostBySlug(slug) {
|
|
41
|
-
try {
|
|
42
|
-
const [post] = await db.select({
|
|
43
|
-
id: postsTable.id,
|
|
44
|
-
title: postsTable.title,
|
|
45
|
-
slug: postsTable.slug,
|
|
46
|
-
content: postsTable.content,
|
|
47
|
-
createdAt: postsTable.createdAt,
|
|
48
|
-
author: {
|
|
49
|
-
name: userTable.name
|
|
50
|
-
}
|
|
51
|
-
}).from(postsTable).innerJoin(userTable, eq(postsTable.authorId, userTable.id)).where(eq(postsTable.slug, slug));
|
|
52
|
-
return post || null;
|
|
53
|
-
} catch (error) {
|
|
54
|
-
console.error("[BlogModule:Actions] getPostBySlug failed:", error);
|
|
55
|
-
throw error;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
export async function getPostById(id) {
|
|
59
|
-
try {
|
|
60
|
-
const [post] = await db.select().from(postsTable).where(eq(postsTable.id, id));
|
|
61
|
-
return post || null;
|
|
62
|
-
} catch (error) {
|
|
63
|
-
console.error("[BlogModule:Actions] getPostById failed:", error);
|
|
64
|
-
throw error;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
export async function getComments(postId) {
|
|
68
|
-
try {
|
|
69
|
-
return await db.select({
|
|
70
|
-
id: commentsTable.id,
|
|
71
|
-
content: commentsTable.content,
|
|
72
|
-
createdAt: commentsTable.createdAt,
|
|
73
|
-
author: {
|
|
74
|
-
name: userTable.name,
|
|
75
|
-
image: userTable.image
|
|
76
|
-
}
|
|
77
|
-
}).from(commentsTable).innerJoin(userTable, eq(commentsTable.authorId, userTable.id)).where(eq(commentsTable.postId, postId)).orderBy(desc(commentsTable.createdAt));
|
|
78
|
-
} catch (error) {
|
|
79
|
-
console.error("[BlogModule:Actions] getComments failed:", error);
|
|
80
|
-
throw error;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
export async function createComment(data) {
|
|
84
|
-
try {
|
|
85
|
-
const { user } = await getCurrentSession();
|
|
86
|
-
if (!user) throw new Error("Must be logged in to comment");
|
|
87
|
-
const validated = commentSchema.parse(data);
|
|
88
|
-
await db.insert(commentsTable).values({
|
|
89
|
-
content: validated.content,
|
|
90
|
-
postId: validated.postId,
|
|
91
|
-
authorId: user.id
|
|
92
|
-
});
|
|
93
|
-
revalidatePath(`/blog`);
|
|
94
|
-
return { success: true };
|
|
95
|
-
} catch (error) {
|
|
96
|
-
console.error("[BlogModule:Actions] createComment failed:", error);
|
|
97
|
-
return { success: false, error: error.message };
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
export async function deletePost(id) {
|
|
101
|
-
try {
|
|
102
|
-
await db.delete(postsTable).where(eq(postsTable.id, id));
|
|
103
|
-
revalidatePath("/blog");
|
|
104
|
-
return { success: true };
|
|
105
|
-
} catch (error) {
|
|
106
|
-
console.error("[BlogModule:Actions] deletePost failed:", error);
|
|
107
|
-
return { success: false, error: error.message };
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
export async function updatePost(id, data) {
|
|
111
|
-
try {
|
|
112
|
-
const validated = postSchema.parse(data);
|
|
113
|
-
await db.update(postsTable).set(validated).where(eq(postsTable.id, id));
|
|
114
|
-
revalidatePath("/blog");
|
|
115
|
-
revalidatePath(`/blog/${validated.slug}`);
|
|
116
|
-
return { success: true };
|
|
117
|
-
} catch (error) {
|
|
118
|
-
console.error("[BlogModule:Actions] updatePost failed:", error);
|
|
119
|
-
return { success: false, error: error.message };
|
|
120
|
-
}
|
|
121
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
module.exports = BlogStatsWidget;
|
|
7
|
-
var _server = require("@arch-cadre/core/server");
|
|
8
|
-
var _server2 = require("@arch-cadre/intl/server");
|
|
9
|
-
var _ui = require("@arch-cadre/ui");
|
|
10
|
-
var _drizzleOrm = require("drizzle-orm");
|
|
11
|
-
var _lucideReact = require("lucide-react");
|
|
12
|
-
var React = _interopRequireWildcard(require("react"));
|
|
13
|
-
var _schema = require("../schema.cjs");
|
|
14
|
-
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
15
|
-
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
16
|
-
async function BlogStatsWidget() {
|
|
17
|
-
const {
|
|
18
|
-
t
|
|
19
|
-
} = await (0, _server2.getTranslation)();
|
|
20
|
-
const [postsCount] = await _server.db.select({
|
|
21
|
-
count: (0, _drizzleOrm.sql)`count(*)`
|
|
22
|
-
}).from(_schema.postsTable);
|
|
23
|
-
const [commentsCount] = await _server.db.select({
|
|
24
|
-
count: (0, _drizzleOrm.sql)`count(*)`
|
|
25
|
-
}).from(_schema.commentsTable);
|
|
26
|
-
return /* @__PURE__ */React.createElement("div", {
|
|
27
|
-
className: "grid gap-4 md:grid-cols-2 lg:grid-cols-2"
|
|
28
|
-
}, /* @__PURE__ */React.createElement(_ui.Card, null, /* @__PURE__ */React.createElement(_ui.CardHeader, {
|
|
29
|
-
className: "flex flex-row items-center justify-between space-y-0 pb-2"
|
|
30
|
-
}, /* @__PURE__ */React.createElement(_ui.CardTitle, {
|
|
31
|
-
className: "text-sm font-medium"
|
|
32
|
-
}, t("Total Posts")), /* @__PURE__ */React.createElement(_lucideReact.FileText, {
|
|
33
|
-
className: "h-4 w-4 text-muted-foreground"
|
|
34
|
-
})), /* @__PURE__ */React.createElement(_ui.CardContent, null, /* @__PURE__ */React.createElement("div", {
|
|
35
|
-
className: "text-2xl font-bold"
|
|
36
|
-
}, postsCount?.count || 0))), /* @__PURE__ */React.createElement(_ui.Card, null, /* @__PURE__ */React.createElement(_ui.CardHeader, {
|
|
37
|
-
className: "flex flex-row items-center justify-between space-y-0 pb-2"
|
|
38
|
-
}, /* @__PURE__ */React.createElement(_ui.CardTitle, {
|
|
39
|
-
className: "text-sm font-medium"
|
|
40
|
-
}, t("Total Comments")), /* @__PURE__ */React.createElement(_lucideReact.MessageSquare, {
|
|
41
|
-
className: "h-4 w-4 text-muted-foreground"
|
|
42
|
-
})), /* @__PURE__ */React.createElement(_ui.CardContent, null, /* @__PURE__ */React.createElement("div", {
|
|
43
|
-
className: "text-2xl font-bold"
|
|
44
|
-
}, commentsCount?.count || 0))));
|
|
45
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { db } from "@arch-cadre/core/server";
|
|
2
|
-
import { getTranslation } from "@arch-cadre/intl/server";
|
|
3
|
-
import { Card, CardContent, CardHeader, CardTitle } from "@arch-cadre/ui";
|
|
4
|
-
import { sql } from "drizzle-orm";
|
|
5
|
-
import { FileText, MessageSquare } from "lucide-react";
|
|
6
|
-
import * as React from "react";
|
|
7
|
-
import { commentsTable, postsTable } from "../schema.mjs";
|
|
8
|
-
export default async function BlogStatsWidget() {
|
|
9
|
-
const { t } = await getTranslation();
|
|
10
|
-
const [postsCount] = await db.select({ count: sql`count(*)` }).from(postsTable);
|
|
11
|
-
const [commentsCount] = await db.select({ count: sql`count(*)` }).from(commentsTable);
|
|
12
|
-
return /* @__PURE__ */ React.createElement("div", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-2" }, /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2" }, /* @__PURE__ */ React.createElement(CardTitle, { className: "text-sm font-medium" }, t("Total Posts")), /* @__PURE__ */ React.createElement(FileText, { className: "h-4 w-4 text-muted-foreground" })), /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement("div", { className: "text-2xl font-bold" }, postsCount?.count || 0))), /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2" }, /* @__PURE__ */ React.createElement(CardTitle, { className: "text-sm font-medium" }, t("Total Comments")), /* @__PURE__ */ React.createElement(MessageSquare, { className: "h-4 w-4 text-muted-foreground" })), /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement("div", { className: "text-2xl font-bold" }, commentsCount?.count || 0))));
|
|
13
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
module.exports = RecentCommentsWidget;
|
|
7
|
-
var _server = require("@arch-cadre/core/server");
|
|
8
|
-
var _server2 = require("@arch-cadre/intl/server");
|
|
9
|
-
var _ui = require("@arch-cadre/ui");
|
|
10
|
-
var _drizzleOrm = require("drizzle-orm");
|
|
11
|
-
var React = _interopRequireWildcard(require("react"));
|
|
12
|
-
var _schema = require("../schema.cjs");
|
|
13
|
-
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
14
|
-
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
15
|
-
async function RecentCommentsWidget() {
|
|
16
|
-
const {
|
|
17
|
-
t
|
|
18
|
-
} = await (0, _server2.getTranslation)();
|
|
19
|
-
const comments = await _server.db.select({
|
|
20
|
-
id: _schema.commentsTable.id,
|
|
21
|
-
content: _schema.commentsTable.content,
|
|
22
|
-
createdAt: _schema.commentsTable.createdAt,
|
|
23
|
-
author: {
|
|
24
|
-
name: _server.userTable.name,
|
|
25
|
-
image: _server.userTable.image
|
|
26
|
-
}
|
|
27
|
-
}).from(_schema.commentsTable).leftJoin(_server.userTable, (0, _drizzleOrm.eq)(_schema.commentsTable.authorId, _server.userTable.id)).orderBy((0, _drizzleOrm.desc)(_schema.commentsTable.createdAt)).limit(5);
|
|
28
|
-
return /* @__PURE__ */React.createElement(_ui.Card, null, /* @__PURE__ */React.createElement(_ui.CardHeader, null, /* @__PURE__ */React.createElement(_ui.CardTitle, null, t("Recent Comments")), /* @__PURE__ */React.createElement(_ui.CardDescription, null, t("What readers are saying about your posts."))), /* @__PURE__ */React.createElement(_ui.CardContent, {
|
|
29
|
-
className: "grid gap-8"
|
|
30
|
-
}, comments.map(comment => /* @__PURE__ */React.createElement("div", {
|
|
31
|
-
key: comment.id,
|
|
32
|
-
className: "flex items-center gap-4"
|
|
33
|
-
}, /* @__PURE__ */React.createElement(_ui.Avatar, {
|
|
34
|
-
className: "h-9 w-9"
|
|
35
|
-
}, /* @__PURE__ */React.createElement(_ui.AvatarImage, {
|
|
36
|
-
src: comment.author?.image || "",
|
|
37
|
-
alt: "Avatar"
|
|
38
|
-
}), /* @__PURE__ */React.createElement(_ui.AvatarFallback, null, comment.author?.name?.substring(0, 2).toUpperCase() || "CM")), /* @__PURE__ */React.createElement("div", {
|
|
39
|
-
className: "grid gap-1"
|
|
40
|
-
}, /* @__PURE__ */React.createElement("p", {
|
|
41
|
-
className: "text-sm font-medium leading-none line-clamp-1"
|
|
42
|
-
}, comment.content), /* @__PURE__ */React.createElement("p", {
|
|
43
|
-
className: "text-sm text-muted-foreground"
|
|
44
|
-
}, comment.author?.name || t("Anonymous"), " \u2022", " ", new Date(comment.createdAt).toLocaleDateString())))), comments.length === 0 && /* @__PURE__ */React.createElement("div", {
|
|
45
|
-
className: "text-center py-4 text-muted-foreground"
|
|
46
|
-
}, t("No comments yet."))));
|
|
47
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { db, userTable } from "@arch-cadre/core/server";
|
|
2
|
-
import { getTranslation } from "@arch-cadre/intl/server";
|
|
3
|
-
import {
|
|
4
|
-
Avatar,
|
|
5
|
-
AvatarFallback,
|
|
6
|
-
AvatarImage,
|
|
7
|
-
Card,
|
|
8
|
-
CardContent,
|
|
9
|
-
CardDescription,
|
|
10
|
-
CardHeader,
|
|
11
|
-
CardTitle
|
|
12
|
-
} from "@arch-cadre/ui";
|
|
13
|
-
import { desc, eq } from "drizzle-orm";
|
|
14
|
-
import * as React from "react";
|
|
15
|
-
import { commentsTable } from "../schema.mjs";
|
|
16
|
-
export default async function RecentCommentsWidget() {
|
|
17
|
-
const { t } = await getTranslation();
|
|
18
|
-
const comments = await db.select({
|
|
19
|
-
id: commentsTable.id,
|
|
20
|
-
content: commentsTable.content,
|
|
21
|
-
createdAt: commentsTable.createdAt,
|
|
22
|
-
author: {
|
|
23
|
-
name: userTable.name,
|
|
24
|
-
image: userTable.image
|
|
25
|
-
}
|
|
26
|
-
}).from(commentsTable).leftJoin(userTable, eq(commentsTable.authorId, userTable.id)).orderBy(desc(commentsTable.createdAt)).limit(5);
|
|
27
|
-
return /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(CardHeader, null, /* @__PURE__ */ React.createElement(CardTitle, null, t("Recent Comments")), /* @__PURE__ */ React.createElement(CardDescription, null, t("What readers are saying about your posts."))), /* @__PURE__ */ React.createElement(CardContent, { className: "grid gap-8" }, comments.map((comment) => /* @__PURE__ */ React.createElement("div", { key: comment.id, className: "flex items-center gap-4" }, /* @__PURE__ */ React.createElement(Avatar, { className: "h-9 w-9" }, /* @__PURE__ */ React.createElement(AvatarImage, { src: comment.author?.image || "", alt: "Avatar" }), /* @__PURE__ */ React.createElement(AvatarFallback, null, comment.author?.name?.substring(0, 2).toUpperCase() || "CM")), /* @__PURE__ */ React.createElement("div", { className: "grid gap-1" }, /* @__PURE__ */ React.createElement("p", { className: "text-sm font-medium leading-none line-clamp-1" }, comment.content), /* @__PURE__ */ React.createElement("p", { className: "text-sm text-muted-foreground" }, comment.author?.name || t("Anonymous"), " \u2022", " ", new Date(comment.createdAt).toLocaleDateString())))), comments.length === 0 && /* @__PURE__ */ React.createElement("div", { className: "text-center py-4 text-muted-foreground" }, t("No comments yet."))));
|
|
28
|
-
}
|