blog and create blog page structure updated
This commit is contained in:
parent
e259461c0a
commit
4ab9fd5264
104
app/(defaults)/(blog)/blog/page.tsx
Normal file
104
app/(defaults)/(blog)/blog/page.tsx
Normal file
@ -0,0 +1,104 @@
|
||||
import { Metadata } from 'next';
|
||||
import Link from 'next/link';
|
||||
import React from 'react';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Blog',
|
||||
};
|
||||
|
||||
const blogs = [
|
||||
{
|
||||
id: 1,
|
||||
image: '/assets/images/blog/image-1.jpg',
|
||||
title: 'Excessive sugar is harmful',
|
||||
description: 'Sugar consumption can have serious effects on your health if taken in excess. Learn how to reduce it.',
|
||||
author: 'Alma Clark',
|
||||
profile: '/assets/images/profile-1.jpeg',
|
||||
date: '06 May',
|
||||
slug: '/blog/1',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
image: '/assets/images/blog/image-1.jpg',
|
||||
title: 'Creative Photography',
|
||||
description: 'Photography is not just about capturing pictures, but emotions and stories through your lens.',
|
||||
author: 'Alma Clark',
|
||||
profile: '/assets/images/profile-2.jpeg',
|
||||
date: '06 May',
|
||||
slug: '/blog/2',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
image: '/assets/images/blog/image-1.jpg',
|
||||
title: 'Plan your next trip',
|
||||
description: 'Traveling helps you explore new cultures, food, and make memories that last a lifetime.',
|
||||
author: 'Alma Clark',
|
||||
profile: '/assets/images/profile-3.jpeg',
|
||||
date: '06 May',
|
||||
slug: '/blog/3',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
image: '/assets/images/blog/image-1.jpg',
|
||||
title: 'My latest Vlog',
|
||||
description: 'Check out my latest vlog where I share behind-the-scenes of my daily life and adventures.',
|
||||
author: 'Alma Clark',
|
||||
profile: '/assets/images/profile-4.jpeg',
|
||||
date: '06 May',
|
||||
slug: '/blog/4',
|
||||
},
|
||||
];
|
||||
|
||||
const Blog = () => {
|
||||
return (
|
||||
<div className="mt-10">
|
||||
<h3 className="mb-6 text-xl font-bold md:text-3xl">Blogs</h3>
|
||||
<div className="grid grid-cols-1 gap-5 sm:grid-cols-2 xl:grid-cols-4">
|
||||
{/* ✅ First box: Create New Blog */}
|
||||
<Link href="/create-blog" className="flex items-center justify-center space-y-5 rounded-md border border-dashed border-blue-500 bg-blue-50 p-5 text-center shadow hover:bg-blue-100 transition dark:border-blue-800 dark:bg-blue-900 dark:hover:bg-blue-800">
|
||||
<div>
|
||||
<div className="mb-3 text-5xl text-blue-600 dark:text-white">+</div>
|
||||
<h5 className="text-lg font-semibold text-blue-800 dark:text-white">Create New Blog</h5>
|
||||
</div>
|
||||
</Link>
|
||||
{blogs.map((blog) => (
|
||||
<div
|
||||
key={blog.id}
|
||||
className="space-y-4 rounded-md border border-white-light bg-white p-5 shadow-[0px_0px_2px_0px_rgba(145,158,171,0.20),0px_12px_24px_-4px_rgba(145,158,171,0.12)] dark:border-[#1B2E4B] dark:bg-black"
|
||||
>
|
||||
<div className="max-h-56 overflow-hidden rounded-md">
|
||||
<img src={blog.image} alt={blog.title} className="w-full object-cover" />
|
||||
</div>
|
||||
|
||||
{/* ✅ Description first, then Title */}
|
||||
<h5 className="text-lg font-semibold dark:text-white">{blog.title}</h5>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">{blog.description}</p>
|
||||
|
||||
{/*
|
||||
<div className="flex items-center">
|
||||
<div className="me-4 overflow-hidden rounded-full bg-white-dark">
|
||||
<img src={blog.profile} className="h-11 w-11 object-cover" alt={blog.author} />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h4 className="mb-1.5 font-semibold dark:text-white">{blog.author}</h4>
|
||||
<p className="text-xs text-gray-500">{blog.date}</p>
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
{/* ✅ Read More button */}
|
||||
<div>
|
||||
<Link
|
||||
href={blog.slug}
|
||||
className="inline-block mt-3 rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700"
|
||||
>
|
||||
Read More
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Blog;
|
||||
196
app/(defaults)/(blog)/create-blog/page.tsx
Normal file
196
app/(defaults)/(blog)/create-blog/page.tsx
Normal file
@ -0,0 +1,196 @@
|
||||
"use client";
|
||||
import IconTrashLines from "@/components/icon/icon-trash-lines";
|
||||
import React, { useState } from "react";
|
||||
import ReactQuill from "react-quill";
|
||||
import "react-quill/dist/quill.snow.css";
|
||||
|
||||
// Custom toolbar options
|
||||
const modules = {
|
||||
toolbar: {
|
||||
container: [
|
||||
[{ header: [1, 2, 3, false] }],
|
||||
["bold", "italic", "underline", "strike"],
|
||||
[{ list: "ordered" }, { list: "bullet" }],
|
||||
["blockquote", "code-block"],
|
||||
[{ align: [] }],
|
||||
["link", "image", "video"],
|
||||
["clean"],
|
||||
],
|
||||
handlers: {
|
||||
image: function () {
|
||||
const input = document.createElement("input");
|
||||
input.setAttribute("type", "file");
|
||||
input.setAttribute("accept", "image/*");
|
||||
input.click();
|
||||
|
||||
input.onchange = async () => {
|
||||
const file = input.files?.[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
const quill = this.quill;
|
||||
const range = quill.getSelection();
|
||||
quill.insertEmbed(range.index, "image", reader.result);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const formats = [
|
||||
"header",
|
||||
"bold", "italic", "underline", "strike",
|
||||
"blockquote", "code-block",
|
||||
"list", "bullet",
|
||||
"align",
|
||||
"link", "image", "video",
|
||||
];
|
||||
|
||||
const PostForm = () => {
|
||||
const [formData, setFormData] = useState({
|
||||
title: "",
|
||||
slug: "",
|
||||
coverImage: null as File | null,
|
||||
description: "",
|
||||
});
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
[name]: value,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0] || null;
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
coverImage: file,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleRemoveImage = () => {
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
coverImage: null,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleDescriptionChange = (value: string) => {
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
description: value,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
const data = new FormData();
|
||||
data.append("title", formData.title);
|
||||
data.append("slug", formData.slug);
|
||||
if (formData.coverImage) {
|
||||
data.append("coverImage", formData.coverImage);
|
||||
}
|
||||
data.append("description", formData.description);
|
||||
|
||||
console.log("FormData prepared:", {
|
||||
title: formData.title,
|
||||
slug: formData.slug,
|
||||
coverImage: formData.coverImage?.name,
|
||||
description: formData.description,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
className="space-y-5 max-w-4xl mx-auto p-6 bg-white rounded shadow-md"
|
||||
>
|
||||
<h2 className="text-xl font-bold mb-4">Create Blog</h2>
|
||||
{/* Blog Title */}
|
||||
<div>
|
||||
<label className="block font-medium mb-1">Blog Title</label>
|
||||
<input
|
||||
type="text"
|
||||
name="title"
|
||||
value={formData.title}
|
||||
onChange={handleChange}
|
||||
placeholder="Enter blog title"
|
||||
className="w-full border rounded-md px-3 py-2 focus:ring-2 focus:ring-blue-500 outline-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Slug */}
|
||||
<div>
|
||||
<label className="block font-medium mb-1">Slug</label>
|
||||
<input
|
||||
type="text"
|
||||
name="slug"
|
||||
value={formData.slug}
|
||||
onChange={handleChange}
|
||||
placeholder="Enter slug (e.g. my-first-blog)"
|
||||
className="w-full border rounded-md px-3 py-2 focus:ring-2 focus:ring-green-500 outline-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Cover Image Upload */}
|
||||
<div>
|
||||
<label className="block font-medium mb-1">Cover Image</label>
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
onChange={handleImageChange}
|
||||
className="w-full border rounded-md px-3 py-2 focus:ring-2 focus:ring-blue-500 outline-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Show Image Preview */}
|
||||
{formData.coverImage && (
|
||||
<div className="mt-3">
|
||||
<p className="text-sm font-medium">Preview:</p>
|
||||
<div className="relative inline-block mt-2">
|
||||
<img
|
||||
src={URL.createObjectURL(formData.coverImage)}
|
||||
alt="Selected"
|
||||
className="w-48 h-32 object-cover rounded border"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleRemoveImage}
|
||||
className="absolute top-1 right-1 bg-red-600 text-white text-xs px-2 py-1 rounded hover:bg-red-700"
|
||||
>
|
||||
<IconTrashLines className="shrink-0" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Description (ReactQuill) */}
|
||||
<div className="mb-5">
|
||||
<ReactQuill
|
||||
value={formData.description}
|
||||
onChange={handleDescriptionChange}
|
||||
modules={modules}
|
||||
formats={formats}
|
||||
placeholder="Write your description..."
|
||||
className="bg-white text-black rounded-md"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Submit Button */}
|
||||
<button
|
||||
type="submit"
|
||||
className="bg-blue-600 text-white px-6 py-2 mt-5 rounded-md hover:bg-blue-700 transition"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default PostForm;
|
||||
@ -249,12 +249,36 @@ const Sidebar = () => {
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
{/* <h2 className="-mx-4 mb-1 flex items-center bg-white-light/30 px-7 py-3 font-extrabold uppercase dark:bg-dark dark:bg-opacity-[0.08]">
|
||||
<h2 className="-mx-4 mb-1 flex items-center bg-white-light/30 px-7 py-3 font-extrabold uppercase dark:bg-dark dark:bg-opacity-[0.08]">
|
||||
<IconMinus className="hidden h-5 w-4 flex-none" />
|
||||
<span>{t('user_interface')}</span>
|
||||
<span>{t('blog')}</span>
|
||||
</h2>
|
||||
|
||||
<li className="menu nav-item">
|
||||
<button type="button" className={`${currentMenu === 'blog' ? 'active' : ''} nav-link group w-full`} onClick={() => toggleMenu('blog')}>
|
||||
<div className="flex items-center">
|
||||
<IconMenuInvoice className="shrink-0 group-hover:!text-primary" />
|
||||
<span className="text-black ltr:pl-3 rtl:pr-3 dark:text-[#506690] dark:group-hover:text-white-dark">{t('Blog')}</span>
|
||||
</div>
|
||||
|
||||
<div className={currentMenu !== 'blog' ? '-rotate-90 rtl:rotate-90' : ''}>
|
||||
<IconCaretDown />
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<AnimateHeight duration={300} height={currentMenu === 'blog' ? 'auto' : 0}>
|
||||
<ul className="sub-menu text-gray-500">
|
||||
<li>
|
||||
<Link href="/blog">{t('list')}</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/create-blog">{t('add')}</Link>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</AnimateHeight>
|
||||
</li>
|
||||
|
||||
{/* <li className="menu nav-item">
|
||||
<button type="button" className={`${currentMenu === 'component' ? 'active' : ''} nav-link group w-full`} onClick={() => toggleMenu('component')}>
|
||||
<div className="flex items-center">
|
||||
<IconMenuComponents className="shrink-0 group-hover:!text-primary" />
|
||||
@ -549,7 +573,7 @@ const Sidebar = () => {
|
||||
</ul>
|
||||
</AnimateHeight>
|
||||
</li> */}
|
||||
{/*
|
||||
{/*
|
||||
<h2 className="-mx-4 mb-1 flex items-center bg-white-light/30 px-7 py-3 font-extrabold uppercase dark:bg-dark dark:bg-opacity-[0.08]">
|
||||
<IconMinus className="hidden h-5 w-4 flex-none" />
|
||||
<span>{t('user_and_pages')}</span>
|
||||
|
||||
126
package-lock.json
generated
126
package-lock.json
generated
@ -28,6 +28,7 @@
|
||||
"react-i18next": "^15.0.2",
|
||||
"react-perfect-scrollbar": "^1.5.8",
|
||||
"react-popper": "^2.3.0",
|
||||
"react-quill": "^2.0.0",
|
||||
"react-redux": "^9.1.2",
|
||||
"sweetalert2": "^11.22.2",
|
||||
"typescript": "^5.3.3",
|
||||
@ -1063,6 +1064,15 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
|
||||
"integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA=="
|
||||
},
|
||||
"node_modules/@types/quill": {
|
||||
"version": "1.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/quill/-/quill-1.3.10.tgz",
|
||||
"integrity": "sha512-IhW3fPW+bkt9MLNlycw8u8fWb7oO7W5URC9MfZYHBlA24rex9rs23D5DETChu1zvgVdc5ka64ICjJOgQMr6Shw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"parchment": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.10.tgz",
|
||||
@ -2041,6 +2051,15 @@
|
||||
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
||||
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
|
||||
},
|
||||
"node_modules/clone": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/clsx": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||
@ -3134,11 +3153,29 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eventemitter3": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
|
||||
"integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||
},
|
||||
"node_modules/fast-diff": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz",
|
||||
"integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
|
||||
@ -4815,6 +4852,12 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/parchment": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/parchment/-/parchment-1.1.4.tgz",
|
||||
"integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
@ -5271,6 +5314,74 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/quill": {
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/quill/-/quill-1.3.7.tgz",
|
||||
"integrity": "sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"clone": "^2.1.1",
|
||||
"deep-equal": "^1.0.1",
|
||||
"eventemitter3": "^2.0.3",
|
||||
"extend": "^3.0.2",
|
||||
"parchment": "^1.1.4",
|
||||
"quill-delta": "^3.6.2"
|
||||
}
|
||||
},
|
||||
"node_modules/quill-delta": {
|
||||
"version": "3.6.3",
|
||||
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-3.6.3.tgz",
|
||||
"integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"deep-equal": "^1.0.1",
|
||||
"extend": "^3.0.2",
|
||||
"fast-diff": "1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/quill-delta/node_modules/deep-equal": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz",
|
||||
"integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-arguments": "^1.1.1",
|
||||
"is-date-object": "^1.0.5",
|
||||
"is-regex": "^1.1.4",
|
||||
"object-is": "^1.1.5",
|
||||
"object-keys": "^1.1.1",
|
||||
"regexp.prototype.flags": "^1.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/quill/node_modules/deep-equal": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz",
|
||||
"integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-arguments": "^1.1.1",
|
||||
"is-date-object": "^1.0.5",
|
||||
"is-regex": "^1.1.4",
|
||||
"object-is": "^1.1.5",
|
||||
"object-keys": "^1.1.1",
|
||||
"regexp.prototype.flags": "^1.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||
@ -5364,6 +5475,21 @@
|
||||
"react-dom": "^16.8.0 || ^17 || ^18"
|
||||
}
|
||||
},
|
||||
"node_modules/react-quill": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0.tgz",
|
||||
"integrity": "sha512-4qQtv1FtCfLgoD3PXAur5RyxuUbPXQGOHgTlFie3jtxp43mXDtzCKaOgQ3mLyZfi1PUlyjycfivKelFhy13QUg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/quill": "^1.3.10",
|
||||
"lodash": "^4.17.4",
|
||||
"quill": "^1.3.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16 || ^17 || ^18",
|
||||
"react-dom": "^16 || ^17 || ^18"
|
||||
}
|
||||
},
|
||||
"node_modules/react-redux": {
|
||||
"version": "9.1.2",
|
||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz",
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
"react-i18next": "^15.0.2",
|
||||
"react-perfect-scrollbar": "^1.5.8",
|
||||
"react-popper": "^2.3.0",
|
||||
"react-quill": "^2.0.0",
|
||||
"react-redux": "^9.1.2",
|
||||
"sweetalert2": "^11.22.2",
|
||||
"typescript": "^5.3.3",
|
||||
|
||||
BIN
public/assets/images/blog/image-1.jpg
Normal file
BIN
public/assets/images/blog/image-1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
Loading…
x
Reference in New Issue
Block a user