@vilio/blog-module 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/index.cjs +158 -0
- package/dist/actions/index.d.ts +34 -0
- package/dist/actions/index.mjs +121 -0
- package/dist/components/BlogStatsWidget.cjs +45 -0
- package/dist/components/BlogStatsWidget.d.ts +2 -0
- package/dist/components/BlogStatsWidget.mjs +13 -0
- package/dist/components/RecentCommentsWidget.cjs +47 -0
- package/dist/components/RecentCommentsWidget.d.ts +2 -0
- package/dist/components/RecentCommentsWidget.mjs +28 -0
- package/dist/components/RecentPostsWidget.cjs +47 -0
- package/dist/components/RecentPostsWidget.d.ts +2 -0
- package/dist/components/RecentPostsWidget.mjs +28 -0
- package/dist/components/ui/button.cjs +54 -0
- package/dist/components/ui/button.d.ts +11 -0
- package/dist/components/ui/button.mjs +47 -0
- package/dist/components/ui/card.cjs +47 -0
- package/dist/components/ui/card.d.ts +6 -0
- package/dist/components/ui/card.mjs +36 -0
- package/dist/components/ui/input.cjs +24 -0
- package/dist/components/ui/input.d.ts +5 -0
- package/dist/components/ui/input.mjs +17 -0
- package/dist/components/ui/table.cjs +68 -0
- package/dist/components/ui/table.d.ts +8 -0
- package/dist/components/ui/table.mjs +65 -0
- package/dist/components/ui/textarea.cjs +22 -0
- package/dist/components/ui/textarea.d.ts +5 -0
- package/dist/components/ui/textarea.mjs +16 -0
- package/dist/index.cjs +102 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.mjs +97 -0
- package/dist/intl.d.ts +7 -0
- package/dist/lib/utils.cjs +11 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.mjs +5 -0
- package/dist/lib/validation.cjs +16 -0
- package/dist/lib/validation.d.ts +24 -0
- package/dist/lib/validation.mjs +10 -0
- package/dist/navigation.cjs +23 -0
- package/dist/navigation.d.ts +2 -0
- package/dist/navigation.mjs +21 -0
- package/dist/routes.cjs +74 -0
- package/dist/routes.d.ts +3 -0
- package/dist/routes.mjs +68 -0
- package/dist/schema.cjs +62 -0
- package/dist/schema.d.ts +736 -0
- package/dist/schema.mjs +53 -0
- package/dist/styles/globals.css +1 -0
- package/dist/ui/views.cjs +448 -0
- package/dist/ui/views.d.ts +16 -0
- package/dist/ui/views.mjs +237 -0
- package/locales/en/global.json +45 -0
- package/locales/pl/global.json +45 -0
- package/manifest.json +11 -0
- package/package.json +59 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
3
|
+
import { useTranslation } from "@vilio/intl/client";
|
|
4
|
+
import {
|
|
5
|
+
ArrowLeft,
|
|
6
|
+
Eye,
|
|
7
|
+
MessageSquare,
|
|
8
|
+
Pencil,
|
|
9
|
+
Plus,
|
|
10
|
+
Trash2,
|
|
11
|
+
User as UserIcon
|
|
12
|
+
} from "lucide-react";
|
|
13
|
+
import Link from "next/link";
|
|
14
|
+
import { useRouter } from "next/navigation";
|
|
15
|
+
import * as React from "react";
|
|
16
|
+
import { useForm } from "react-hook-form";
|
|
17
|
+
import { toast } from "sonner";
|
|
18
|
+
import {
|
|
19
|
+
createComment,
|
|
20
|
+
createPost,
|
|
21
|
+
deletePost,
|
|
22
|
+
updatePost
|
|
23
|
+
} from "../actions/index.mjs";
|
|
24
|
+
import { Button } from "../components/ui/button.mjs";
|
|
25
|
+
import {
|
|
26
|
+
Card,
|
|
27
|
+
CardContent,
|
|
28
|
+
CardHeader,
|
|
29
|
+
CardTitle
|
|
30
|
+
} from "../components/ui/card.mjs";
|
|
31
|
+
import { Input } from "../components/ui/input.mjs";
|
|
32
|
+
import {
|
|
33
|
+
Table,
|
|
34
|
+
TableBody,
|
|
35
|
+
TableCell,
|
|
36
|
+
TableHead,
|
|
37
|
+
TableHeader,
|
|
38
|
+
TableRow
|
|
39
|
+
} from "../components/ui/table.mjs";
|
|
40
|
+
import { Textarea } from "../components/ui/textarea.mjs";
|
|
41
|
+
import { commentSchema, postSchema } from "../lib/validation.mjs";
|
|
42
|
+
export function BlogListPage({ posts = [] }) {
|
|
43
|
+
const { t } = useTranslation();
|
|
44
|
+
return /* @__PURE__ */ React.createElement("div", { className: "max-w-4xl mx-auto p-6 space-y-8" }, /* @__PURE__ */ React.createElement("header", { className: "border-b pb-6" }, /* @__PURE__ */ React.createElement("h1", { className: "text-4xl font-black tracking-tighter text-primary" }, t("Blog Posts")), /* @__PURE__ */ React.createElement("p", { className: "text-muted-foreground mt-2" }, t("Reading your blog posts"))), /* @__PURE__ */ React.createElement("div", { className: "grid gap-6" }, posts.map((post) => /* @__PURE__ */ React.createElement(Link, { href: `/blog/${post.slug}`, key: post.id }, /* @__PURE__ */ React.createElement(Card, { className: "group hover:shadow-lg transition-all cursor-pointer overflow-hidden border-primary/5" }, /* @__PURE__ */ React.createElement(CardHeader, null, /* @__PURE__ */ React.createElement(CardTitle, { className: "text-2xl group-hover:text-primary transition-colors" }, post.title), /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 text-xs text-muted-foreground mt-1" }, /* @__PURE__ */ React.createElement(UserIcon, { className: "size-3" }), /* @__PURE__ */ React.createElement("span", null, post.author?.name), /* @__PURE__ */ React.createElement("span", null, "\u2022"), /* @__PURE__ */ React.createElement("span", null, new Date(post.createdAt).toLocaleDateString()))), /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement("p", { className: "text-secondary-foreground line-clamp-2" }, post.content)))))));
|
|
45
|
+
}
|
|
46
|
+
function CommentForm({ postId }) {
|
|
47
|
+
const router = useRouter();
|
|
48
|
+
const { t } = useTranslation();
|
|
49
|
+
const {
|
|
50
|
+
register,
|
|
51
|
+
handleSubmit,
|
|
52
|
+
reset,
|
|
53
|
+
formState: { errors, isSubmitting }
|
|
54
|
+
} = useForm({
|
|
55
|
+
resolver: zodResolver(commentSchema.omit({ postId: true }))
|
|
56
|
+
});
|
|
57
|
+
const onSubmit = async (data) => {
|
|
58
|
+
const result = await createComment({ ...data, postId });
|
|
59
|
+
if (result.success) {
|
|
60
|
+
toast.success(t("Comment added"));
|
|
61
|
+
reset();
|
|
62
|
+
router.refresh();
|
|
63
|
+
} else {
|
|
64
|
+
toast.error(result.error);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
return /* @__PURE__ */ React.createElement("form", { onSubmit: handleSubmit(onSubmit), className: "space-y-4" }, /* @__PURE__ */ React.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ React.createElement(
|
|
68
|
+
Textarea,
|
|
69
|
+
{
|
|
70
|
+
...register("content"),
|
|
71
|
+
placeholder: t("Add your comment here..."),
|
|
72
|
+
className: errors.content ? "border-destructive" : ""
|
|
73
|
+
}
|
|
74
|
+
), errors.content && /* @__PURE__ */ React.createElement("p", { className: "text-xs text-destructive" }, errors.content.message)), /* @__PURE__ */ React.createElement(Button, { type: "submit", disabled: isSubmitting, size: "sm" }, isSubmitting ? t("Please wait...") : t("Create Comment")));
|
|
75
|
+
}
|
|
76
|
+
export function PostDetailPage({
|
|
77
|
+
post,
|
|
78
|
+
comments = [],
|
|
79
|
+
currentUser
|
|
80
|
+
}) {
|
|
81
|
+
const { t } = useTranslation();
|
|
82
|
+
if (!post)
|
|
83
|
+
return /* @__PURE__ */ React.createElement("div", { className: "p-20 text-center" }, t("Post not found"));
|
|
84
|
+
return /* @__PURE__ */ React.createElement("div", { className: "max-w-3xl mx-auto p-6 space-y-10 pb-20" }, /* @__PURE__ */ React.createElement(Button, { asChild: true, variant: "ghost", size: "sm", className: "gap-2" }, /* @__PURE__ */ React.createElement(Link, { href: "/blog" }, /* @__PURE__ */ React.createElement(ArrowLeft, { className: "size-4" }), " ", t("Back to posts"))), /* @__PURE__ */ React.createElement("article", { className: "space-y-6" }, /* @__PURE__ */ React.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React.createElement("h1", { className: "text-5xl font-black tracking-tighter leading-tight" }, post.title), /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-3 text-muted-foreground" }, /* @__PURE__ */ React.createElement("div", { className: "size-8 rounded-full bg-primary/10 flex items-center justify-center" }, /* @__PURE__ */ React.createElement(UserIcon, { className: "size-4 text-primary" })), /* @__PURE__ */ React.createElement("div", { className: "text-sm" }, /* @__PURE__ */ React.createElement("p", { className: "font-bold text-foreground leading-none" }, post.author?.name), /* @__PURE__ */ React.createElement("p", { className: "text-xs" }, new Date(post.createdAt).toLocaleDateString())))), /* @__PURE__ */ React.createElement("div", { className: "prose prose-lg dark:prose-invert max-w-none whitespace-pre-wrap pt-4 border-t" }, post.content)), /* @__PURE__ */ React.createElement("section", { className: "pt-10 border-t space-y-8" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement(MessageSquare, { className: "size-5" }), /* @__PURE__ */ React.createElement("h3", { className: "text-2xl font-bold tracking-tight" }, t("Comments"), " (", comments.length, ")")), currentUser ? /* @__PURE__ */ React.createElement("div", { className: "bg-muted/30 p-6 rounded-2xl border" }, /* @__PURE__ */ React.createElement("p", { className: "text-sm font-bold mb-4" }, t("Leave a comment")), /* @__PURE__ */ React.createElement(CommentForm, { postId: post.id })) : /* @__PURE__ */ React.createElement("div", { className: "p-6 bg-amber-50 border border-amber-100 rounded-2xl text-center" }, /* @__PURE__ */ React.createElement("p", { className: "text-sm font-medium text-amber-800" }, "Please", " ", /* @__PURE__ */ React.createElement(Link, { href: "/signin", className: "underline font-bold" }, t("Sign in")), " ", t("to join the conversation."))), /* @__PURE__ */ React.createElement("div", { className: "space-y-6" }, comments.map((comment) => /* @__PURE__ */ React.createElement("div", { key: comment.id, className: "flex gap-4" }, /* @__PURE__ */ React.createElement("div", { className: "size-10 rounded-full bg-muted flex items-center justify-center shrink-0" }, /* @__PURE__ */ React.createElement(UserIcon, { className: "size-5 opacity-40" })), /* @__PURE__ */ React.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement("span", { className: "font-bold text-sm" }, comment.author?.name), /* @__PURE__ */ React.createElement("span", { className: "text-[10px] opacity-50" }, new Date(comment.createdAt).toLocaleDateString())), /* @__PURE__ */ React.createElement("p", { className: "text-sm text-secondary-foreground leading-relaxed" }, comment.content)))), comments.length === 0 && /* @__PURE__ */ React.createElement("p", { className: "text-center text-muted-foreground text-sm py-10 italic" }, t("No comments yet. Be the first to comment!")))));
|
|
85
|
+
}
|
|
86
|
+
export function BlogAdminPage({ posts = [] }) {
|
|
87
|
+
const router = useRouter();
|
|
88
|
+
const { t } = useTranslation();
|
|
89
|
+
const handleDelete = async (id) => {
|
|
90
|
+
if (!confirm(t("Confirm deletion of this post?"))) return;
|
|
91
|
+
const result = await deletePost(id);
|
|
92
|
+
if (result.success) {
|
|
93
|
+
toast.success(t("Post deleted"));
|
|
94
|
+
router.refresh();
|
|
95
|
+
} else {
|
|
96
|
+
toast.error(t("UnexpectedError") + result.error);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
return /* @__PURE__ */ React.createElement("div", { className: "p-6 space-y-6" }, /* @__PURE__ */ React.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React.createElement("h1", { className: "text-3xl font-black tracking-tight text-foreground" }, t("Blog posts")), /* @__PURE__ */ React.createElement(Button, { asChild: true, size: "sm", className: "gap-2" }, /* @__PURE__ */ React.createElement(Link, { href: "/vilio/blog/new" }, /* @__PURE__ */ React.createElement(Plus, { className: "size-4" }), " ", t("New Post")))), /* @__PURE__ */ React.createElement(Card, { className: "border-primary/10 shadow-sm overflow-hidden" }, /* @__PURE__ */ React.createElement(Table, null, /* @__PURE__ */ React.createElement(TableHeader, null, /* @__PURE__ */ React.createElement(TableRow, null, /* @__PURE__ */ React.createElement(TableHead, { className: "w-[40%]" }, t("Title")), /* @__PURE__ */ React.createElement(TableHead, null, t("Author")), /* @__PURE__ */ React.createElement(TableHead, null, t("Date")), /* @__PURE__ */ React.createElement(TableHead, { className: "text-right" }, t("Actions")))), /* @__PURE__ */ React.createElement(TableBody, null, posts.length === 0 && /* @__PURE__ */ React.createElement(TableRow, null, /* @__PURE__ */ React.createElement(
|
|
100
|
+
TableCell,
|
|
101
|
+
{
|
|
102
|
+
colSpan: 4,
|
|
103
|
+
className: "h-24 text-center text-muted-foreground italic"
|
|
104
|
+
},
|
|
105
|
+
t("No posts found. Create your first post!")
|
|
106
|
+
)), posts.map((post) => /* @__PURE__ */ React.createElement(TableRow, { key: post.id, className: "transition-colors" }, /* @__PURE__ */ React.createElement(TableCell, { className: "font-bold" }, post.title), /* @__PURE__ */ React.createElement(TableCell, { className: "text-xs" }, post.author?.name), /* @__PURE__ */ React.createElement(TableCell, { className: "text-muted-foreground text-xs" }, new Date(post.createdAt).toLocaleDateString()), /* @__PURE__ */ React.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React.createElement("div", { className: "flex justify-end gap-2" }, /* @__PURE__ */ React.createElement(
|
|
107
|
+
Button,
|
|
108
|
+
{
|
|
109
|
+
asChild: true,
|
|
110
|
+
variant: "ghost",
|
|
111
|
+
size: "icon",
|
|
112
|
+
className: "size-8"
|
|
113
|
+
},
|
|
114
|
+
/* @__PURE__ */ React.createElement(Link, { href: `/blog/${post.slug}`, target: "_blank" }, /* @__PURE__ */ React.createElement(Eye, { className: "size-4" }))
|
|
115
|
+
), /* @__PURE__ */ React.createElement(
|
|
116
|
+
Button,
|
|
117
|
+
{
|
|
118
|
+
asChild: true,
|
|
119
|
+
variant: "ghost",
|
|
120
|
+
size: "icon",
|
|
121
|
+
className: "size-8"
|
|
122
|
+
},
|
|
123
|
+
/* @__PURE__ */ React.createElement(Link, { href: `/vilio/blog/edit/${post.id}` }, /* @__PURE__ */ React.createElement(Pencil, { className: "size-4" }))
|
|
124
|
+
), /* @__PURE__ */ React.createElement(
|
|
125
|
+
Button,
|
|
126
|
+
{
|
|
127
|
+
variant: "ghost",
|
|
128
|
+
size: "icon",
|
|
129
|
+
className: "size-8 text-destructive hover:text-destructive hover:bg-destructive/10",
|
|
130
|
+
onClick: () => handleDelete(post.id)
|
|
131
|
+
},
|
|
132
|
+
/* @__PURE__ */ React.createElement(Trash2, { className: "size-4" })
|
|
133
|
+
)))))))));
|
|
134
|
+
}
|
|
135
|
+
export function CreatePostForm() {
|
|
136
|
+
const router = useRouter();
|
|
137
|
+
const { t } = useTranslation();
|
|
138
|
+
const {
|
|
139
|
+
register,
|
|
140
|
+
handleSubmit,
|
|
141
|
+
formState: { errors, isSubmitting }
|
|
142
|
+
} = useForm({
|
|
143
|
+
resolver: zodResolver(postSchema.omit({ slug: true }))
|
|
144
|
+
});
|
|
145
|
+
const onSubmit = async (data) => {
|
|
146
|
+
const slug = data.title.toLowerCase().replace(/ /g, "-").replace(/[^\w-]+/g, "");
|
|
147
|
+
const result = await createPost({ ...data, slug });
|
|
148
|
+
if (result.success) {
|
|
149
|
+
toast.success(t("Post created"));
|
|
150
|
+
router.push("/vilio/blog");
|
|
151
|
+
router.refresh();
|
|
152
|
+
} else {
|
|
153
|
+
toast.error(t("UnexpectedError") + result.error);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
return /* @__PURE__ */ React.createElement("div", { className: "max-w-2xl mx-auto p-6 space-y-6" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React.createElement(Button, { asChild: true, variant: "outline", size: "icon", className: "rounded-lg" }, /* @__PURE__ */ React.createElement(Link, { href: "/vilio/blog" }, /* @__PURE__ */ React.createElement(ArrowLeft, { className: "size-4" }))), /* @__PURE__ */ React.createElement("h1", { className: "text-2xl font-black text-foreground" }, t("New Post"))), /* @__PURE__ */ React.createElement(Card, { className: "border-primary/10 shadow-lg" }, /* @__PURE__ */ React.createElement(CardContent, { className: "pt-6" }, /* @__PURE__ */ React.createElement("form", { onSubmit: handleSubmit(onSubmit), className: "space-y-6" }, /* @__PURE__ */ React.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React.createElement("label", { className: "text-xs font-black uppercase tracking-widest opacity-50 px-1" }, t("Title")), /* @__PURE__ */ React.createElement(
|
|
157
|
+
Input,
|
|
158
|
+
{
|
|
159
|
+
...register("title"),
|
|
160
|
+
className: errors.title ? "border-destructive font-bold" : "font-bold",
|
|
161
|
+
placeholder: t("Title of your post")
|
|
162
|
+
}
|
|
163
|
+
), errors.title && /* @__PURE__ */ React.createElement("p", { className: "text-xs text-destructive font-bold" }, errors.title.message)), /* @__PURE__ */ React.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React.createElement("label", { className: "text-xs font-black uppercase tracking-widest opacity-50 px-1" }, t("Content")), /* @__PURE__ */ React.createElement(
|
|
164
|
+
Textarea,
|
|
165
|
+
{
|
|
166
|
+
...register("content"),
|
|
167
|
+
rows: 12,
|
|
168
|
+
className: errors.content ? "border-destructive resize-none" : "resize-none",
|
|
169
|
+
placeholder: t("Content of your post")
|
|
170
|
+
}
|
|
171
|
+
), errors.content && /* @__PURE__ */ React.createElement("p", { className: "text-xs text-destructive font-bold" }, errors.content.message)), /* @__PURE__ */ React.createElement(
|
|
172
|
+
Button,
|
|
173
|
+
{
|
|
174
|
+
type: "submit",
|
|
175
|
+
disabled: isSubmitting,
|
|
176
|
+
className: "w-full text-sm uppercase tracking-widest transition-all"
|
|
177
|
+
},
|
|
178
|
+
isSubmitting ? t("Please wait...") : t("Publish")
|
|
179
|
+
)))));
|
|
180
|
+
}
|
|
181
|
+
export function EditPostForm({ post }) {
|
|
182
|
+
const router = useRouter();
|
|
183
|
+
const { t } = useTranslation();
|
|
184
|
+
const {
|
|
185
|
+
register,
|
|
186
|
+
handleSubmit,
|
|
187
|
+
formState: { errors, isSubmitting }
|
|
188
|
+
} = useForm({
|
|
189
|
+
resolver: zodResolver(postSchema),
|
|
190
|
+
defaultValues: {
|
|
191
|
+
title: post.title,
|
|
192
|
+
content: post.content,
|
|
193
|
+
slug: post.slug
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
const onSubmit = async (data) => {
|
|
197
|
+
const result = await updatePost(post.id, data);
|
|
198
|
+
if (result.success) {
|
|
199
|
+
toast.success(t("Post updated"));
|
|
200
|
+
router.push("/vilio/blog");
|
|
201
|
+
router.refresh();
|
|
202
|
+
} else {
|
|
203
|
+
toast.error(t("UnexpectedError") + result.error);
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
return /* @__PURE__ */ React.createElement("div", { className: "max-w-2xl mx-auto p-6 space-y-6" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React.createElement(Button, { asChild: true, variant: "outline", size: "icon", className: "rounded-lg" }, /* @__PURE__ */ React.createElement(Link, { href: "/vilio/blog" }, /* @__PURE__ */ React.createElement(ArrowLeft, { className: "size-4" }))), /* @__PURE__ */ React.createElement("h1", { className: "text-2xl font-black text-foreground" }, t("Edit Post"))), /* @__PURE__ */ React.createElement(Card, { className: "border-primary/10 shadow-lg" }, /* @__PURE__ */ React.createElement(CardContent, { className: "pt-6" }, /* @__PURE__ */ React.createElement("form", { onSubmit: handleSubmit(onSubmit), className: "space-y-6" }, /* @__PURE__ */ React.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React.createElement("label", { className: "text-xs font-black uppercase tracking-widest opacity-50 px-1" }, t("Title")), /* @__PURE__ */ React.createElement(
|
|
207
|
+
Input,
|
|
208
|
+
{
|
|
209
|
+
...register("title"),
|
|
210
|
+
className: errors.title ? "border-destructive font-bold" : "font-bold",
|
|
211
|
+
placeholder: t("Title of your post")
|
|
212
|
+
}
|
|
213
|
+
), errors.title && /* @__PURE__ */ React.createElement("p", { className: "text-xs text-destructive font-bold" }, errors.title.message)), /* @__PURE__ */ React.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React.createElement("label", { className: "text-xs font-black uppercase tracking-widest opacity-50 px-1" }, t("Slug")), /* @__PURE__ */ React.createElement(
|
|
214
|
+
Input,
|
|
215
|
+
{
|
|
216
|
+
...register("slug"),
|
|
217
|
+
className: errors.slug ? "border-destructive font-mono text-sm" : "font-mono text-sm",
|
|
218
|
+
placeholder: t("Slug URL")
|
|
219
|
+
}
|
|
220
|
+
), errors.slug && /* @__PURE__ */ React.createElement("p", { className: "text-xs text-destructive font-bold" }, errors.slug.message)), /* @__PURE__ */ React.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React.createElement("label", { className: "text-xs font-black uppercase tracking-widest opacity-50 px-1" }, t("Content")), /* @__PURE__ */ React.createElement(
|
|
221
|
+
Textarea,
|
|
222
|
+
{
|
|
223
|
+
...register("content"),
|
|
224
|
+
rows: 12,
|
|
225
|
+
className: errors.content ? "border-destructive resize-none" : "resize-none",
|
|
226
|
+
placeholder: t("Content of your post")
|
|
227
|
+
}
|
|
228
|
+
), errors.content && /* @__PURE__ */ React.createElement("p", { className: "text-xs text-destructive font-bold" }, errors.content.message)), /* @__PURE__ */ React.createElement(
|
|
229
|
+
Button,
|
|
230
|
+
{
|
|
231
|
+
type: "submit",
|
|
232
|
+
disabled: isSubmitting,
|
|
233
|
+
className: "w-full text-sm uppercase tracking-widest transition-all"
|
|
234
|
+
},
|
|
235
|
+
isSubmitting ? t("Please wait...") : t("Update")
|
|
236
|
+
)))));
|
|
237
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Blog Posts": "Blog Posts",
|
|
3
|
+
"Reading your blog posts": "Reading your blog posts",
|
|
4
|
+
"Comment added": "Comment added",
|
|
5
|
+
"Add your comment here...": "Add your comment here...",
|
|
6
|
+
"Create Comment": "Create Comment",
|
|
7
|
+
"Post not found": "Post not found",
|
|
8
|
+
"Back to posts": "Back to posts",
|
|
9
|
+
"Comments": "Comments",
|
|
10
|
+
"Leave a comment": "Leave a comment",
|
|
11
|
+
"Sign in": "Sign in",
|
|
12
|
+
"to join the conversation.": "to join the conversation.",
|
|
13
|
+
"No comments yet. Be the first to comment!": "No comments yet. Be the first to comment!",
|
|
14
|
+
"Confirm deletion of this post?": "Confirm deletion of this post?",
|
|
15
|
+
"Post deleted": "Post deleted",
|
|
16
|
+
"Blog posts": "Blog posts",
|
|
17
|
+
"New Post": "New Post",
|
|
18
|
+
"Title": "Title",
|
|
19
|
+
"Author": "Author",
|
|
20
|
+
"Date": "Date",
|
|
21
|
+
"Actions": "Actions",
|
|
22
|
+
"No posts found. Create your first post!": "No posts found. Create your first post!",
|
|
23
|
+
"Post created": "Post created",
|
|
24
|
+
"Title of your post": "Title of your post",
|
|
25
|
+
"Content": "Content",
|
|
26
|
+
"Content of your post": "Content of your post",
|
|
27
|
+
"Publish": "Publish",
|
|
28
|
+
"Post updated": "Post updated",
|
|
29
|
+
"Edit Post": "Edit Post",
|
|
30
|
+
"Slug": "Slug",
|
|
31
|
+
"Slug URL": "Slug URL",
|
|
32
|
+
"Update": "Update",
|
|
33
|
+
"Blog": "Blog",
|
|
34
|
+
"CMS": "CMS",
|
|
35
|
+
"Blog Manager": "Blog Manager",
|
|
36
|
+
"Recent Posts": "Recent Posts",
|
|
37
|
+
"The latest articles published on your blog.": "The latest articles published on your blog.",
|
|
38
|
+
"No posts found.": "No posts found.",
|
|
39
|
+
"Recent Comments": "Recent Comments",
|
|
40
|
+
"What readers are saying about your posts.": "What readers are saying about your posts.",
|
|
41
|
+
"No comments yet.": "No comments yet.",
|
|
42
|
+
"Anonymous": "Anonymous",
|
|
43
|
+
"Total Posts": "Total Posts",
|
|
44
|
+
"Total Comments": "Total Comments"
|
|
45
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Blog Posts": "Posty na blogu",
|
|
3
|
+
"Reading your blog posts": "Czytając Twoje posty na blogu",
|
|
4
|
+
"Comment added": "Komentarz dodany",
|
|
5
|
+
"Add your comment here...": "Dodaj tutaj swój komentarz...",
|
|
6
|
+
"Create Comment": "Utwórz komentarz",
|
|
7
|
+
"Post not found": "Nie znaleziono wpisu",
|
|
8
|
+
"Back to posts": "Powrót do postów",
|
|
9
|
+
"Comments": "Uwagi",
|
|
10
|
+
"Leave a comment": "Zostaw komentarz",
|
|
11
|
+
"Sign in": "Zalogować się",
|
|
12
|
+
"to join the conversation.": "aby dołączyć do rozmowy.",
|
|
13
|
+
"No comments yet. Be the first to comment!": "Nie ma jeszcze żadnych komentarzy. Bądź pierwszą osobą, która skomentuje!",
|
|
14
|
+
"Confirm deletion of this post?": "Potwierdzić usunięcie tego wpisu?",
|
|
15
|
+
"Post deleted": "Post został usunięty",
|
|
16
|
+
"Blog posts": "Posty na blogu",
|
|
17
|
+
"New Post": "Nowy post",
|
|
18
|
+
"Title": "Tytuł",
|
|
19
|
+
"Author": "Autor",
|
|
20
|
+
"Date": "Data",
|
|
21
|
+
"Actions": "Działania",
|
|
22
|
+
"No posts found. Create your first post!": "Nie znaleziono żadnych postów. Utwórz swój pierwszy post!",
|
|
23
|
+
"Post created": "Wpis został utworzony",
|
|
24
|
+
"Title of your post": "Tytuł Twojego postu",
|
|
25
|
+
"Content": "Treść",
|
|
26
|
+
"Content of your post": "Treść Twojego wpisu",
|
|
27
|
+
"Publish": "Publikować",
|
|
28
|
+
"Post updated": "Wpis zaktualizowany",
|
|
29
|
+
"Edit Post": "Edytuj post",
|
|
30
|
+
"Slug": "Przyjazny adres URL",
|
|
31
|
+
"Slug URL": "Przyjazny adres URL",
|
|
32
|
+
"Update": "Aktualizacja",
|
|
33
|
+
"Blog": "Bloga",
|
|
34
|
+
"CMS": "CMS-a",
|
|
35
|
+
"Blog Manager": "Menedżer bloga",
|
|
36
|
+
"Recent Posts": "Ostatnie wpisy",
|
|
37
|
+
"The latest articles published on your blog.": "Najnowsze artykuły opublikowane na Twoim blogu.",
|
|
38
|
+
"No posts found.": "Nie znaleziono wpisów.",
|
|
39
|
+
"Recent Comments": "Ostatnie komentarze",
|
|
40
|
+
"What readers are saying about your posts.": "Co czytelnicy mówią o Twoich wpisach.",
|
|
41
|
+
"No comments yet.": "Brak komentarzy.",
|
|
42
|
+
"Anonymous": "Anonimowy",
|
|
43
|
+
"Total Posts": "Wszystkie wpisy",
|
|
44
|
+
"Total Comments": "Wszystkie komentarze"
|
|
45
|
+
}
|
package/manifest.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vilio/blog-module",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "A sample module for Vilio framework",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"main": "./dist/index.mjs",
|
|
8
|
+
"exports": {
|
|
9
|
+
"./package.json": "./package.json",
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.cjs"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"locales",
|
|
18
|
+
"manifest.json"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"release": "npm publish --access public --no-git-checks",
|
|
22
|
+
"clean": "rm -rf ./dist",
|
|
23
|
+
"switch:dev": "node scripts/switchToSrc.js",
|
|
24
|
+
"switch:prod": "node scripts/switchToDist.js",
|
|
25
|
+
"build": "unbuild",
|
|
26
|
+
"devs": "unbuild --stub",
|
|
27
|
+
"builds": "pnpm clean && tsc --module esnext"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@vilio/core": "^0.0.4",
|
|
31
|
+
"@vilio/modules": "^0.0.4",
|
|
32
|
+
"@hookform/resolvers": "^3.10.0",
|
|
33
|
+
"@radix-ui/react-slot": "^1.2.3",
|
|
34
|
+
"class-variance-authority": "^0.7.1",
|
|
35
|
+
"clsx": "^2.1.1",
|
|
36
|
+
"drizzle-orm": "1.0.0-beta.6-4414a19",
|
|
37
|
+
"lucide-react": "^0.475.0",
|
|
38
|
+
"pg": "^8.18.0",
|
|
39
|
+
"react-hook-form": "^7.54.2",
|
|
40
|
+
"sonner": "^2.0.7",
|
|
41
|
+
"tailwind-merge": "^1.14.0",
|
|
42
|
+
"tw-animate-css": "^1.3.6",
|
|
43
|
+
"zod": "^3.24.1"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/pg": "^8.16.0",
|
|
47
|
+
"@types/react": "^19",
|
|
48
|
+
"next": "16.1.1",
|
|
49
|
+
"react": "^19.0.0",
|
|
50
|
+
"typescript": "^5.3.3",
|
|
51
|
+
"unbuild": "^3.6.1"
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"@vilio/core": "^0.0.4",
|
|
55
|
+
"@vilio/intl": "^0.0.4",
|
|
56
|
+
"@vilio/ui": "^0.0.4",
|
|
57
|
+
"react": "^19.0.0"
|
|
58
|
+
}
|
|
59
|
+
}
|