Merge branch 'Performing-task-Text-and-Image' of WrenchBoard/WrenchBoardMainSite into master
This commit is contained in:
@@ -0,0 +1,33 @@
|
|||||||
|
:root {
|
||||||
|
--loader-width: auto;
|
||||||
|
--loader-height: auto;
|
||||||
|
--text-container-width: 400px;
|
||||||
|
--text-container-height: auto;
|
||||||
|
--line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-skeleton-loader,
|
||||||
|
.blog-text-skeleton-loader {
|
||||||
|
width: var(--loader-width);
|
||||||
|
height: var(--loader-height);
|
||||||
|
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
|
||||||
|
background-size: 200% 100%;
|
||||||
|
animation: loading 1.5s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-skeleton-loader{
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-text-skeleton-loader {
|
||||||
|
line-height: calc(var(--text-container-height) * var(--line-height));
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loading {
|
||||||
|
0% {
|
||||||
|
background-position: -200% 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: 200% 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
+51
-10
@@ -1,21 +1,62 @@
|
|||||||
import React from "react";
|
|
||||||
import singlePost from "../../assets/images/single-post/1.jpg";
|
import singlePost from "../../assets/images/single-post/1.jpg";
|
||||||
|
import { BlogLoader, ImageLoader } from "../../lib/SkeletonLoaders";
|
||||||
|
import LazyImage from "../../lib/LazyImage";
|
||||||
|
|
||||||
function Blog({ blogItem, imgUrl }) {
|
/**
|
||||||
const blogImg =
|
* Renders a blog post component.
|
||||||
blogItem?.meta_value != null
|
* @returns {JSX.Element} The rendered blog post component.
|
||||||
? `${imgUrl}/${blogItem?.meta_value}`
|
*/
|
||||||
: singlePost;
|
function Blog({ blogItem, imgUrl, loader }) {
|
||||||
|
// Generate a unique ID
|
||||||
|
const uniqueId = `element_${Math.random().toString(36).substr(2, 9)}`;
|
||||||
|
|
||||||
|
const blogImg = `${imgUrl}/${blogItem?.meta_value || singlePost}`;
|
||||||
|
|
||||||
|
const imgLoaderStyles = {
|
||||||
|
"--loader-width": "750px",
|
||||||
|
"--loader-height": "550px",
|
||||||
|
};
|
||||||
|
|
||||||
|
const headerLoaderStyles = {
|
||||||
|
"--text-container-width": "300px",
|
||||||
|
"--text-container-height": "34px",
|
||||||
|
};
|
||||||
|
|
||||||
|
const bodyTextLoaderStyles = {
|
||||||
|
"--text-container-width": "770px",
|
||||||
|
"--text-container-height": "150px",
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="single-post-area">
|
<div className="single-post-area">
|
||||||
<div className="post-thumb" style={{marginTop : "0"}}>
|
<div className="post-thumb" style={{ marginTop: "0" }}>
|
||||||
<img src={blogImg} alt="" />
|
{loader ? (
|
||||||
|
<div style={imgLoaderStyles}>
|
||||||
|
<ImageLoader />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<LazyImage src={blogImg} alt={blogItem?.meta_value || "single-post.jpg"} key={uniqueId} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<h4 className="article-title">{blogItem?.post_title}</h4>
|
{loader ? (
|
||||||
<div dangerouslySetInnerHTML={{ __html: blogItem?.post_content }}></div>
|
<div style={headerLoaderStyles}>
|
||||||
|
<BlogLoader />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<h4 className="article-title">{blogItem?.post_title}</h4>
|
||||||
|
)}
|
||||||
|
{loader ? (
|
||||||
|
<div style={bodyTextLoaderStyles}>
|
||||||
|
<BlogLoader />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
dangerouslySetInnerHTML={{ __html: blogItem?.post_content }}
|
||||||
|
></div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* <blockquote>
|
{/* <blockquote>
|
||||||
<p>
|
<p>
|
||||||
I don't want no agro brilliant are you taking the piss skive off super
|
I don't want no agro brilliant are you taking the piss skive off super
|
||||||
|
|||||||
@@ -16,16 +16,20 @@ import StickyHeaderNav from "../StickyHeader/StickyHeaderNav";
|
|||||||
*/
|
*/
|
||||||
function BlogDetail() {
|
function BlogDetail() {
|
||||||
const [drawer, drawerAction] = useToggle(false);
|
const [drawer, drawerAction] = useToggle(false);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [blogs, setBlogs] = useState([]);
|
const [blogs, setBlogs] = useState([]);
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchBlogs = async () => {
|
const fetchBlogs = async () => {
|
||||||
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const res = await BlogData();
|
const res = await BlogData();
|
||||||
setBlogs(res.data);
|
setBlogs(res.data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("Error loading blogdata", err);
|
console.log("Error loading blogdata", err);
|
||||||
|
} finally {
|
||||||
|
setTimeout(() => setIsLoading(false), 1500);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -52,7 +56,7 @@ function BlogDetail() {
|
|||||||
{ link: "/blog", title: "Blogs" },
|
{ link: "/blog", title: "Blogs" },
|
||||||
{
|
{
|
||||||
link: `/blog/blogdetail/${id}`,
|
link: `/blog/blogdetail/${id}`,
|
||||||
title: blogItem ? blogItem.post_title : "Post not found",
|
title: isLoading ? "please wait..." : blogItem ? blogItem.post_title : "Post not found",
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
@@ -62,7 +66,7 @@ function BlogDetail() {
|
|||||||
<div className="container">
|
<div className="container">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-lg-8 col-md-7">
|
<div className="col-lg-8 col-md-7">
|
||||||
<Blog blogItem={blogItem} imgUrl={blogs?.image_url} />
|
<Blog blogItem={blogItem} imgUrl={blogs?.image_url} loader={isLoading} />
|
||||||
</div>
|
</div>
|
||||||
<div className="col-lg-4 col-md-5">
|
<div className="col-lg-4 col-md-5">
|
||||||
<BlogSideBar blogs={blogs} />
|
<BlogSideBar blogs={blogs} />
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ function Blogs({ pathname }) {
|
|||||||
const renderBlogs = () => {
|
const renderBlogs = () => {
|
||||||
return blogs?.blogdata?.map((blog, index) => {
|
return blogs?.blogdata?.map((blog, index) => {
|
||||||
const options = {
|
const options = {
|
||||||
weekday: "long",
|
weekday: "short",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
month: "long",
|
month: "long",
|
||||||
day: "numeric",
|
day: "numeric",
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders an image lazily using the Intersection Observer API.
|
||||||
|
* The image is initially hidden and becomes visible once it enters the viewport.
|
||||||
|
* This approach improves performance by only loading images that are actually visible to the user.
|
||||||
|
*
|
||||||
|
* @returns {JSX.Element} - The lazy image component.
|
||||||
|
*/
|
||||||
|
function LazyImage({ src, alt }) {
|
||||||
|
const imgRef = useRef();
|
||||||
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
const [entry] = entries;
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
setIsVisible(true);
|
||||||
|
observer.unobserve(imgRef.current); // Stop observing once the image is in the viewport
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
root: null, // Viewport
|
||||||
|
rootMargin: '0px', // No margin
|
||||||
|
threshold: 0.1, // Percentage of the image that needs to be visible
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (imgRef.current) {
|
||||||
|
observer.observe(imgRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (imgRef.current) {
|
||||||
|
observer.unobserve(imgRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
ref={imgRef}
|
||||||
|
src={isVisible ? src : ''}
|
||||||
|
alt={alt}
|
||||||
|
loading="lazy"
|
||||||
|
className={isVisible ? 'visible' : 'hidden'} // You can apply CSS classes for animations
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LazyImage;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import "../assets/css/skeleton-loader.css"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a placeholder `<div>` element with the class name "image-skeleton-loader".
|
||||||
|
* This component is typically used as a placeholder for an image while it is being loaded.
|
||||||
|
* The CSS class "image-skeleton-loader or blog-text-skeleton-loader" can be used to style the placeholder element.
|
||||||
|
*
|
||||||
|
* @returns {React.Element} The rendered `<div>` element with the class name "image-skeleton-loader or blog-text-skeleton-loader".
|
||||||
|
*/
|
||||||
|
export const ImageLoader = () => <div className="image-skeleton-loader" />;
|
||||||
|
|
||||||
|
export const BlogLoader = () => <div className="blog-text-skeleton-loader" />
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user