Added preliminary image support and improved functionality around application
This commit is contained in:
parent
2d8cc1e7de
commit
d450ac3cb4
@ -93,7 +93,6 @@ class BlogsByCategoryAPIView(APIView):
|
||||
class BlogCreateAPIView(generics.CreateAPIView):
|
||||
queryset = Blog.objects.all()
|
||||
serializer_class = BlogSerializer
|
||||
lookup_field = 'blog_id'
|
||||
|
||||
class BlogUpdateAPIView(generics.RetrieveUpdateAPIView):
|
||||
queryset = Blog.objects.all()
|
||||
@ -105,16 +104,6 @@ class BlogRetrieveAPIView(generics.RetrieveAPIView):
|
||||
serializer_class = BlogSerializer
|
||||
lookup_field = 'blog_id'
|
||||
|
||||
class CategoryDetailView(APIView):
|
||||
def get(self, request, category_id):
|
||||
try:
|
||||
category = Category.objects.get(category_id=category_id)
|
||||
except Category.DoesNotExist:
|
||||
return Response({'message': 'Category not found'}, status=404)
|
||||
|
||||
serializer = UnifiedCategoryBlogSerializer(category)
|
||||
return Response(serializer.data)
|
||||
|
||||
class BlogDeleteAPIView(generics.DestroyAPIView):
|
||||
queryset = Blog.objects.all()
|
||||
serializer_class = BlogSerializer
|
||||
|
||||
@ -45,8 +45,8 @@ urlpatterns = [
|
||||
path('data/category/<slug:category_id>/', BlogsByCategoryAPIView.as_view(), name='blogs-by-category-view'),
|
||||
path('data/category/update/<slug:category_id>/', CategoryUpdateAPIView.as_view(), name='category-update-view'),
|
||||
path('data/category/delete/<slug:category_id>/', CategoryDeleteAPIView.as_view(), name='category-delete-view'),
|
||||
path('data/blog/create/', BlogCreateAPIView.as_view(), name='blog-create-view'),
|
||||
path('data/blog/<slug:blog_id>/', BlogRetrieveAPIView.as_view(), name='blog-retrieve-view'),
|
||||
path('data/blog/create/<slug:blog_id>/', BlogCreateAPIView.as_view(), name='blog-create-view'),
|
||||
path('data/blog/update/<slug:blog_id>/', BlogUpdateAPIView.as_view(), name='blog-update-view'),
|
||||
path('data/blog/delete/<slug:blog_id>/', BlogDeleteAPIView.as_view(), name='blog-delete-view'),
|
||||
]
|
||||
56
frontend/package-lock.json
generated
56
frontend/package-lock.json
generated
@ -14,7 +14,7 @@
|
||||
"@tiptap/extension-blockquote": "^2.3.2",
|
||||
"@tiptap/extension-color": "^2.3.2",
|
||||
"@tiptap/extension-highlight": "^2.3.2",
|
||||
"@tiptap/extension-image": "^2.3.2",
|
||||
"@tiptap/extension-image": "^2.4.0",
|
||||
"@tiptap/extension-link": "^2.3.2",
|
||||
"@tiptap/extension-list-item": "^2.3.2",
|
||||
"@tiptap/extension-text-align": "^2.3.2",
|
||||
@ -25,8 +25,10 @@
|
||||
"axios": "^1.6.8",
|
||||
"bootstrap": "^5.3.3",
|
||||
"html-react-parser": "^5.1.10",
|
||||
"interactjs": "^1.10.27",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-resizable": "^3.0.5",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"reactstrap": "^9.2.2",
|
||||
"sass": "^1.75.0",
|
||||
@ -920,6 +922,11 @@
|
||||
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@interactjs/types": {
|
||||
"version": "1.10.27",
|
||||
"resolved": "https://registry.npmjs.org/@interactjs/types/-/types-1.10.27.tgz",
|
||||
"integrity": "sha512-BUdv0cvs4H5ODuwft2Xp4eL8Vmi3LcihK42z0Ft/FbVJZoRioBsxH+LlsBdK4tAie7PqlKGy+1oyOncu1nQ6eA=="
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
|
||||
@ -1453,9 +1460,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-image": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-image/-/extension-image-2.3.2.tgz",
|
||||
"integrity": "sha512-otkhqToHnjjpWOIswuotfK/PTPEOhhKRFPf1NuXvqHpMNulz+J1uIuA9R/B1m+bXkxZzCMKkWQi50vjqH9idVg==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-image/-/extension-image-2.4.0.tgz",
|
||||
"integrity": "sha512-NIVhRPMO/ONo8OywEd+8zh0Q6Q7EbFHtBxVsvfOKj9KtZkaXQfUO4MzONTyptkvAchTpj9pIzeaEY5fyU87gFA==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
@ -2211,6 +2218,14 @@
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
||||
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="
|
||||
},
|
||||
"node_modules/clsx": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
||||
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
@ -3501,6 +3516,14 @@
|
||||
"resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.3.tgz",
|
||||
"integrity": "sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g=="
|
||||
},
|
||||
"node_modules/interactjs": {
|
||||
"version": "1.10.27",
|
||||
"resolved": "https://registry.npmjs.org/interactjs/-/interactjs-1.10.27.tgz",
|
||||
"integrity": "sha512-y/8RcCftGAF24gSp76X2JS3XpHiUvDQyhF8i7ujemBz77hwiHDuJzftHx7thY8cxGogwGiPJ+o97kWB6eAXnsA==",
|
||||
"dependencies": {
|
||||
"@interactjs/types": "1.10.27"
|
||||
}
|
||||
},
|
||||
"node_modules/internal-slot": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
|
||||
@ -4706,6 +4729,19 @@
|
||||
"react": "^18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-draggable": {
|
||||
"version": "4.4.6",
|
||||
"resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.6.tgz",
|
||||
"integrity": "sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==",
|
||||
"dependencies": {
|
||||
"clsx": "^1.1.1",
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 16.3.0",
|
||||
"react-dom": ">= 16.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-fast-compare": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
|
||||
@ -4744,6 +4780,18 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-resizable": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/react-resizable/-/react-resizable-3.0.5.tgz",
|
||||
"integrity": "sha512-vKpeHhI5OZvYn82kXOs1bC8aOXktGU5AmKAgaZS4F5JPburCtbmDPqE7Pzp+1kN4+Wb81LlF33VpGwWwtXem+w==",
|
||||
"dependencies": {
|
||||
"prop-types": "15.x",
|
||||
"react-draggable": "^4.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 16.3"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "6.22.3",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz",
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
"@tiptap/extension-blockquote": "^2.3.2",
|
||||
"@tiptap/extension-color": "^2.3.2",
|
||||
"@tiptap/extension-highlight": "^2.3.2",
|
||||
"@tiptap/extension-image": "^2.3.2",
|
||||
"@tiptap/extension-image": "^2.4.0",
|
||||
"@tiptap/extension-link": "^2.3.2",
|
||||
"@tiptap/extension-list-item": "^2.3.2",
|
||||
"@tiptap/extension-text-align": "^2.3.2",
|
||||
@ -30,8 +30,10 @@
|
||||
"axios": "^1.6.8",
|
||||
"bootstrap": "^5.3.3",
|
||||
"html-react-parser": "^5.1.10",
|
||||
"interactjs": "^1.10.27",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-resizable": "^3.0.5",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"reactstrap": "^9.2.2",
|
||||
"sass": "^1.75.0",
|
||||
|
||||
@ -11,24 +11,27 @@ import {
|
||||
Card,
|
||||
Row,
|
||||
Col,
|
||||
Button,
|
||||
CardImg,
|
||||
CardTitle,
|
||||
CardText,
|
||||
CardBody
|
||||
} from 'reactstrap';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { faLeftLong } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
function BlogList(props) {
|
||||
|
||||
const { categoryID } = useParams();
|
||||
let navigate = useNavigate();
|
||||
|
||||
const GlobalTheme = props.GlobalTheme;
|
||||
const ThemeConfig = props.ThemeConfig;
|
||||
|
||||
const [categoryData, setCategoryData] = useState('loading');
|
||||
const [currentPage, setCurrentPage] = useState('loading');
|
||||
|
||||
useEffect(() => {
|
||||
const loadBlogs = () => {
|
||||
EditableDataService.getData(`/data/category/${categoryID}/`).then(response => {
|
||||
let responseData = response.data
|
||||
let blogMetadata = []
|
||||
@ -56,11 +59,32 @@ function BlogList(props) {
|
||||
setCategoryData(localCategoryData)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadBlogs()
|
||||
}, [categoryID]);
|
||||
|
||||
const addNewBlog = () => {
|
||||
EditableDataService.createData(`/data/blog/create/`, {
|
||||
"name": "Enter a blog name",
|
||||
"description": "Enter a description",
|
||||
"tagline": "Enter a tagline",
|
||||
"cover_image": "",
|
||||
"content_body": "<p></p>",
|
||||
"parent_category": categoryID
|
||||
}).then(response => {
|
||||
props.notificationToggler("New blog created")
|
||||
loadBlogs()
|
||||
}).catch(error => {
|
||||
props.notificationToggler('Failed to add a new blog', 'danger');
|
||||
});
|
||||
}
|
||||
|
||||
if (GlobalTheme && ThemeConfig) {
|
||||
return (
|
||||
<Container fluid className={`mb-2 p-0 ${ThemeConfig[GlobalTheme].background}`}>
|
||||
<Col xs="3" className="d-none d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/categories/`)} className="ms-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
|
||||
<CategoryBar currentPage={categoryID} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} />
|
||||
<Row className="justify-content-center align-items-center">
|
||||
<Col className="d-flex flex-column align-items-center">
|
||||
@ -69,6 +93,7 @@ return (
|
||||
<CardBody>
|
||||
<CardTitle style={{ display: "grid" }} className={`${ThemeConfig[GlobalTheme].textColor} justify-content-center`} tag="h1">
|
||||
{`Blogs in ${categoryData.name}`}
|
||||
<Button className='mt-2' color={ThemeConfig[GlobalTheme].buttonColor} outline onClick={() => addNewBlog()}>Add New</Button>
|
||||
</CardTitle>
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
||||
@ -4,14 +4,20 @@ import EditableDataService from '../../services/editable-data-service';
|
||||
import MediaService from '../../services/media-service'
|
||||
import CategoryBar from './shared/category-bar';
|
||||
import EditorComponent from './shared/tiptap';
|
||||
import ModalComponent from './shared/modal-component';
|
||||
|
||||
import { faLeftLong } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
import {
|
||||
Container,Row, Col,Spinner, UncontrolledCollapse, Button, ButtonGroup, Card, CardBody, Input, InputGroup, InputGroupText
|
||||
} from 'reactstrap';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
function Blog(props) {
|
||||
|
||||
let navigate = useNavigate();
|
||||
|
||||
const nameField = useRef(null);
|
||||
const descriptionField = useRef(null);
|
||||
const tagLineField = useRef(null);
|
||||
@ -23,6 +29,11 @@ function Blog(props) {
|
||||
|
||||
const [blogData, setBlogData] = useState([]);
|
||||
const [blogContent, setBlogContent] = useState();
|
||||
const [modal, setModal] = useState(false);
|
||||
const [modalText, setModalText] = useState(false);
|
||||
const [modalTitle, setModalTitle] = useState(false);
|
||||
|
||||
const toggle = () => setModal(!modal);
|
||||
|
||||
const setInfo = (event) => {
|
||||
EditableDataService.updateData(`/data/blog/update/${blogID}/`,{
|
||||
@ -38,6 +49,22 @@ function Blog(props) {
|
||||
});
|
||||
}
|
||||
|
||||
const showModal = () => {
|
||||
setModalTitle('Confirm')
|
||||
setModalText('Are you sure that you wish to delete this blog?')
|
||||
toggle()
|
||||
}
|
||||
|
||||
const deleteResource = () => {
|
||||
EditableDataService.deleteData(`/data/blog/delete/${blogData.id}/`).then(response => {
|
||||
props.notificationToggler('Blog successfully deleted')
|
||||
navigate(`/categories/${blogData.parentCategory}`);
|
||||
}).catch(error => {
|
||||
props.notificationToggler('Failed to delete blog', 'danger');
|
||||
});
|
||||
toggle()
|
||||
}
|
||||
|
||||
const getInfo = () => {
|
||||
EditableDataService.getData(`/data/blog/${blogID}/`).then(response => {
|
||||
let responseData = response.data
|
||||
@ -61,19 +88,25 @@ function Blog(props) {
|
||||
if (GlobalTheme && ThemeConfig && blogData) {
|
||||
return (
|
||||
<Container fluid className={`${ThemeConfig[GlobalTheme].background}`}>
|
||||
<ModalComponent modalText={modalText} modalTitle={modalTitle} modal={modal} toggle={toggle} confirmAction={deleteResource}/>
|
||||
<Col xs="3" className="d-none d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/categories/${blogData.parentCategory}`)} className="ms-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
|
||||
<CategoryBar currentPage={blogData.parentCategory} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig}/>
|
||||
<Row className="mb-4">
|
||||
<Col className="p-0">
|
||||
{
|
||||
blogData.coverImage !== "" ?
|
||||
<img
|
||||
src={MediaService.getMedia(blogData.coverImage)}
|
||||
alt="Banner"
|
||||
style={{ width: '100%', height: 'auto', maxHeight: '20vh', objectFit: 'cover' }}
|
||||
/>
|
||||
/>:""
|
||||
}
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="mr-2 ml-2 mb-2 mt-1 blogContent">
|
||||
<Col xs="3" className="d-none d-md-block"></Col>
|
||||
<Col xs={`${window.screen.width >= 765 ? '6':''}`}>
|
||||
<Button color='danger' onClick={() => showModal()} className="mb-5">Delete Blog</Button>
|
||||
<InputGroup className="mb-3">
|
||||
<InputGroupText>
|
||||
Name
|
||||
|
||||
@ -19,9 +19,13 @@ import {
|
||||
Button,
|
||||
ButtonGroup
|
||||
} from 'reactstrap';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { faLeftLong } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
function Blogs(props) {
|
||||
|
||||
let navigate = useNavigate();
|
||||
const GlobalTheme = props.GlobalTheme;
|
||||
const ThemeConfig = props.ThemeConfig;
|
||||
|
||||
@ -65,7 +69,7 @@ function Blogs(props) {
|
||||
|
||||
const deleteResource = (id) => {
|
||||
EditableDataService.deleteData(`/data/category/delete/${id}/`).then(response => {
|
||||
props.notificationToggler('Category delete successfully')
|
||||
props.notificationToggler('Category successfully deleted')
|
||||
setCategoryData()
|
||||
}).catch(error => {
|
||||
props.notificationToggler('Failed to delete category', 'danger');
|
||||
@ -74,10 +78,10 @@ function Blogs(props) {
|
||||
|
||||
const addNewCategory = () => {
|
||||
EditableDataService.createData('/data/category/create/', {
|
||||
"name": "Enter a blog name",
|
||||
"name": "Enter name",
|
||||
"featured_blog": "",
|
||||
"description": "Enter description",
|
||||
"tagline": "Enter category tagline",
|
||||
"tagline": "Enter tagline",
|
||||
"cover_image": ""
|
||||
}).then(response => {
|
||||
props.notificationToggler('Category created successfully')
|
||||
@ -99,9 +103,10 @@ function Blogs(props) {
|
||||
setCategoryData()
|
||||
}
|
||||
|
||||
if (GlobalTheme && ThemeConfig && categoryMetadata.length > 0) {
|
||||
if (GlobalTheme && ThemeConfig) {
|
||||
return (
|
||||
<Container fluid className={`p-0 mb-2 ${ThemeConfig[GlobalTheme].background}`}>
|
||||
<Col xs="3" className="d-none d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/`)} className="ms-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
|
||||
<Row className="justify-content-center align-items-center">
|
||||
<Col className="d-flex flex-column align-items-center">
|
||||
<div className="w-100">
|
||||
|
||||
@ -116,7 +116,7 @@ function CardListViewer(props) {
|
||||
<Link className={`${props.textColor}`} to={`/${props.resourceType}/${itemObject.id}`}>
|
||||
Open this resource
|
||||
</Link>
|
||||
<Button color={props.buttonColor} onClick={() => showModal()} outline className="m-1">Delete</Button>
|
||||
<Button color='danger' onClick={() => showModal()} className="m-2">Delete Blog</Button>
|
||||
</CardText>
|
||||
</CardBody>
|
||||
</Card>
|
||||
@ -128,13 +128,13 @@ function CardListViewer(props) {
|
||||
{itemObject.coverImage !== "" ? <CardImg src={MediaService.getMedia(itemObject.coverImage)} style={{ "height": "180px", "objectFit": "cover" }} top width="100%" /> : ""}
|
||||
<CardBody>
|
||||
<Link to={`/${props.resourceType}/${itemObject.id}`}>
|
||||
<CardTitle className={`${props.textColor}`} tag="h5">
|
||||
<CardTitle className={`${props.textColor}`} tag="h3">
|
||||
{itemObject.name}
|
||||
</CardTitle>
|
||||
<CardText className={`${props.textColor}`}>
|
||||
<CardText className={`${props.textColor}`} tag="h5">
|
||||
{itemObject.description}
|
||||
</CardText>
|
||||
<CardText>
|
||||
<CardText tag="h6">
|
||||
<small className={`${props.textColor}`}>
|
||||
{itemObject.tagLine}
|
||||
</small>
|
||||
|
||||
@ -8,6 +8,7 @@ import Highlight from '@tiptap/extension-highlight'
|
||||
import TextAlign from '@tiptap/extension-text-align'
|
||||
import Underline from '@tiptap/extension-underline'
|
||||
import Blockquote from '@tiptap/extension-blockquote'
|
||||
import Image from '@tiptap/extension-image'
|
||||
import Link from '@tiptap/extension-link'
|
||||
import { EditorProvider, useCurrentEditor } from '@tiptap/react'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
@ -328,6 +329,12 @@ const extensions = [
|
||||
}),
|
||||
Underline,
|
||||
Blockquote,
|
||||
Image.configure({
|
||||
allowBase64: true,
|
||||
HTMLAttributes: {
|
||||
class: 'mx-auto d-block',
|
||||
},
|
||||
}),
|
||||
TextAlign.configure({
|
||||
types: ['heading', 'paragraph'],
|
||||
}),
|
||||
|
||||
@ -11,15 +11,18 @@ import {
|
||||
Card,
|
||||
Row,
|
||||
Col,
|
||||
CardImg,
|
||||
Button,
|
||||
CardTitle,
|
||||
CardText,
|
||||
CardBody
|
||||
} from 'reactstrap';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { faLeftLong } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
function BlogList(props) {
|
||||
|
||||
let navigate = useNavigate();
|
||||
|
||||
const { categoryID } = useParams();
|
||||
|
||||
const GlobalTheme = props.GlobalTheme;
|
||||
@ -47,6 +50,7 @@ function BlogList(props) {
|
||||
if (GlobalTheme && ThemeConfig) {
|
||||
return (
|
||||
<Container fluid className={` mb-2 p-0 ${ThemeConfig[GlobalTheme].background}`}>
|
||||
<Col xs="3" className="d-none d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/categories`)} className="ms-5 mt-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
|
||||
<CategoryBar currentPage={categoryID} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig}/>
|
||||
<Row className="justify-content-center align-items-center">
|
||||
<Col className="d-flex flex-column align-items-center">
|
||||
|
||||
@ -8,10 +8,13 @@ import CategoryBar from './shared/category-bar';
|
||||
import {
|
||||
Container,Row, Col,Spinner, UncontrolledCollapse, Button, ButtonGroup, Card, CardBody
|
||||
} from 'reactstrap';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import { Link, useParams, useNavigate } from 'react-router-dom';
|
||||
import { faLeftLong } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
function Blog(props) {
|
||||
|
||||
let navigate = useNavigate();
|
||||
const { blogID } = useParams();
|
||||
|
||||
const GlobalTheme = props.GlobalTheme;
|
||||
@ -56,14 +59,18 @@ function Blog(props) {
|
||||
if (GlobalTheme && ThemeConfig) {
|
||||
return (
|
||||
<Container fluid className={`${ThemeConfig[GlobalTheme].background}`}>
|
||||
<Col xs="3" className="d-none d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/categories/${blogData.parentCategory}`)} className="ms-5 mt-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
|
||||
<CategoryBar currentPage={blogData.parentCategory} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig}/>
|
||||
<Row className="mb-4">
|
||||
<Col className="p-0">
|
||||
{
|
||||
blogData.coverImage !== "" ?
|
||||
<img
|
||||
src={MediaService.getMedia(blogData.coverImage)}
|
||||
alt="Banner"
|
||||
style={{ width: '100%', height: 'auto', maxHeight: '20vh', objectFit: 'cover' }}
|
||||
/>
|
||||
/>:""
|
||||
}
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="mr-2 ml-2 mb-2 mt-1 blogContent">
|
||||
@ -142,13 +149,13 @@ function Blog(props) {
|
||||
</Row>
|
||||
|
||||
<Row className="mr-2 ml-2 mt-1">
|
||||
<Col xs="3" className="d-none d-md-block"></Col>
|
||||
<Col xs="4" className="d-none d-md-block"></Col>
|
||||
|
||||
<Col style={{marginBottom: '25px'}}>
|
||||
<div className={`blogContent ${ThemeConfig[GlobalTheme].textColor}`}>{blogContent}</div>
|
||||
</Col>
|
||||
|
||||
<Col xs="3" className="d-none d-md-block"></Col>
|
||||
<Col xs="4" className="d-none d-md-block"></Col>
|
||||
</Row>
|
||||
</Container>
|
||||
);
|
||||
|
||||
@ -15,11 +15,15 @@ import {
|
||||
CardImg,
|
||||
CardTitle,
|
||||
CardText,
|
||||
CardBody
|
||||
CardBody,
|
||||
Button
|
||||
} from 'reactstrap';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { faLeftLong } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
function Blogs(props) {
|
||||
let navigate = useNavigate();
|
||||
const GlobalTheme = props.GlobalTheme;
|
||||
const ThemeConfig = props.ThemeConfig;
|
||||
|
||||
@ -34,10 +38,12 @@ function Blogs(props) {
|
||||
if (GlobalTheme && ThemeConfig) {
|
||||
return (
|
||||
<Container fluid className={`p-0 mb-2 ${ThemeConfig[GlobalTheme].background}`}>
|
||||
|
||||
<Row className="justify-content-center align-items-center">
|
||||
<Col className="d-flex flex-column align-items-center">
|
||||
{/* Top Section - Categories */}
|
||||
<div className="w-100">
|
||||
<Col xs="3" className="d-none d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/`)} className="ms-5 mt-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
|
||||
<Card className={`my-2 ${ThemeConfig[GlobalTheme].background}`} style={{width: "100%", border: "none"}}>
|
||||
<CardBody>
|
||||
<CardTitle style={{ display: "grid" }} className={`${ThemeConfig[GlobalTheme].textColor} justify-content-center`} tag="h1">
|
||||
|
||||
@ -39,3 +39,10 @@ a {
|
||||
border-radius: 10px;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.blogContent img {
|
||||
display: flex;
|
||||
justify-content: center; /* Center horizontally */
|
||||
align-items: center;
|
||||
width: 50%;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user