Commit 2998de23 by Syed Abdul Rahman

dark theme implemented

parent 16708e12
...@@ -2,24 +2,23 @@ import type { Preview } from '@storybook/nextjs' ...@@ -2,24 +2,23 @@ import type { Preview } from '@storybook/nextjs'
import { useEffect } from 'react' import { useEffect } from 'react'
import '../src/app/fonts.css' import '../src/app/fonts.css'
// Decorator to handle theme changes and update HTML attributes
const ThemeDecorator = (Story: any, context: any) => { const ThemeDecorator = (Story: any, context: any) => {
const backgroundValue = context.globals.backgrounds?.value const backgroundValue = context.globals.backgrounds?.value
console.log(backgroundValue,"backgroundValue") console.log(backgroundValue,"backgroundValue")
// Determine theme based on background value // Determine theme based on background value
const theme = backgroundValue === 'dark' ? 'dark-theme' : 'light-theme' const theme = backgroundValue == 'dark' ? 'dark-theme' : ''
useEffect(() => { useEffect(() => {
// Update document root attributes // Update document root attributes
document.documentElement.setAttribute('data-theme', theme) document.documentElement.setAttribute('data-theme', theme)
// Update body attributes // Update body attributes
document.body.setAttribute('data-theme', theme) // document.body.setAttribute('data-theme', theme)
// You can also update specific elements if needed // You can also update specific elements if needed
console.log("happening")
}, [theme]) }, [theme])
console.log("happening")
return Story() return Story()
} }
...@@ -47,7 +46,7 @@ const preview: Preview = { ...@@ -47,7 +46,7 @@ const preview: Preview = {
decorators: [ThemeDecorator], decorators: [ThemeDecorator],
initialGlobals: { initialGlobals: {
backgrounds: { value: '#ffe788' }, backgrounds: { value: 'white' },
}, },
} }
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
"build-storybook": "storybook build" "build-storybook": "storybook build"
}, },
"dependencies": { "dependencies": {
"axios": "^1.10.0",
"next": "15.3.4", "next": "15.3.4",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0" "react-dom": "^19.0.0"
......
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools --> <!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="64px" height="64px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"/> <g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/> <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
<g id="SVGRepo_iconCarrier"> <path d="M8 8L16 16" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M16 8L8 16" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </g> <g id="SVGRepo_iconCarrier"> <path d="M8 8L16 16" stroke="#969696" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M16 8L8 16" stroke="#969696" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </g>
</svg> </svg>
\ No newline at end of file
......
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="64px" height="64px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="#a3a3a3">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
<g id="SVGRepo_iconCarrier"> <path d="M12 7V12L10.5 14.5M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" stroke="#aeadad" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </g>
</svg>
\ No newline at end of file
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
--secondary-bg-color: #f8f9fa; --secondary-bg-color: #f8f9fa;
--primary-text-color: #2d3748; --primary-text-color: #2d3748;
--secondary-text-color: #9d99b3; --secondary-text-color: #9d99b3;
--disabled-button-bg: rgba(115, 40, 255, 0.26);
} }
[data-theme="dark-theme"] { [data-theme="dark-theme"] {
...@@ -10,8 +11,10 @@ ...@@ -10,8 +11,10 @@
--secondary-bg-color: #0b0d0e; --secondary-bg-color: #0b0d0e;
--primary-text-color: #e4e4e4; --primary-text-color: #e4e4e4;
--secondary-text-color: #8fa2ae; --secondary-text-color: #8fa2ae;
--disabled-button-bg: rgba(193, 180, 216, 0.516);
} }
html, html,
body { body {
margin: 0;
} }
import Image from "next/image"; "use client";
import styles from "./page.module.css"; import CardWrapper from "@/components/TopLevel/CardList/CardWrapper/CardWrapper";
import Header from "@/components/Layout/Header/Header"; import Pagination from "@/components/Shared/Pagination/Pagination";
import { useEffect, useState } from "react";
import { getBlogPosts } from "@/lib/Api";
export default function Home() { export default function Home() {
return <div className={styles.page}></div>; const [currentPage, setCurrentPage] = useState(1);
const [posts, setPosts] = useState<any>();
useEffect(() => {
fetchPost();
}, []);
const fetchPost = async () => {
try {
const response = await getBlogPosts();
console.log("response", response);
setPosts(response);
} catch (err) {
console.log(err, "error while fetching data");
}
};
const handlePageChange = (page: any) => {
setCurrentPage(page);
};
return (
<>
<CardWrapper cardData={posts} />
<Pagination
currentPage={currentPage}
totalPages={8}
onPageChange={handlePageChange}
/>
</>
);
} }
...@@ -7,9 +7,9 @@ ...@@ -7,9 +7,9 @@
.button { .button {
border: 0; border: 0;
font-family: "Inter-Medium"; font-family: "Inter-Bold";
cursor: pointer; cursor: pointer;
border-radius: 10px; border-radius: 12px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
.primary:hover { .primary:hover {
color: white; color: white;
background-color: rgb(115, 40, 255) !important; background-color: rgb(115, 101, 243) !important;
} }
.secondary { .secondary {
...@@ -50,13 +50,13 @@ ...@@ -50,13 +50,13 @@
} }
.lg { .lg {
padding: 1rem 2.2rem; padding: 1rem 2.3rem;
font-size: 18px; font-size: 18px;
} }
.button-active { .button-active {
color: white; color: white;
background-color: rgb(115, 40, 255); background-color: rgb(115, 101, 243);
} }
.loader { .loader {
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
} }
.disabled { .disabled {
background-color: rgba(115, 40, 255, 0.26); background-color: var(--disabled-button-bg);
color: gray; color: gray;
pointer-events: none; pointer-events: none;
} }
......
...@@ -10,7 +10,7 @@ export const Primary = { ...@@ -10,7 +10,7 @@ export const Primary = {
render: () => { render: () => {
return ( return (
<> <>
<h2 style={{ fontFamily: "Inter-Medium", color: "gray" }}>Size</h2> <h2 style={{ fontFamily: "Inter-Medium", color: "black" }}>Size</h2>
<section className={styles["btn-wrapper"]}> <section className={styles["btn-wrapper"]}>
<Button variant="primary" size="sm"> <Button variant="primary" size="sm">
Small Small
...@@ -22,7 +22,7 @@ export const Primary = { ...@@ -22,7 +22,7 @@ export const Primary = {
Large Large
</Button> </Button>
</section> </section>
<h2 style={{ fontFamily: "Inter-Medium", color: "gray" }}>Loader</h2> <h2 style={{ fontFamily: "Inter-Medium", color: "black" }}>Loader</h2>
<section className={styles["btn-wrapper"]}> <section className={styles["btn-wrapper"]}>
<Button variant="primary" size="sm" loading={true}> <Button variant="primary" size="sm" loading={true}>
Button Button
...@@ -34,7 +34,7 @@ export const Primary = { ...@@ -34,7 +34,7 @@ export const Primary = {
Button Button
</Button> </Button>
</section> </section>
<h2 style={{ fontFamily: "Inter-Medium", color: "gray" }}>Disabled</h2> <h2 style={{ fontFamily: "Inter-Medium", color: "black" }}>Disabled</h2>
<section className={styles["btn-wrapper"]}> <section className={styles["btn-wrapper"]}>
<Button variant="primary" size="sm" disabled={true}> <Button variant="primary" size="sm" disabled={true}>
Button Button
...@@ -46,7 +46,7 @@ export const Primary = { ...@@ -46,7 +46,7 @@ export const Primary = {
Button Button
</Button> </Button>
</section> </section>
<h2 style={{ fontFamily: "Inter-Medium", color: "gray" }}> <h2 style={{ fontFamily: "Inter-Medium", color: "black" }}>
Loader and Disabled Loader and Disabled
</h2> </h2>
<section className={styles["btn-wrapper"]}> <section className={styles["btn-wrapper"]}>
...@@ -70,7 +70,7 @@ export const Secondary = { ...@@ -70,7 +70,7 @@ export const Secondary = {
render: () => { render: () => {
return ( return (
<> <>
<h2 style={{ fontFamily: "Inter-Medium", color: "gray" }}>Size</h2> <h2 style={{ fontFamily: "Inter-Medium", color: "black" }}>Size</h2>
<section className={styles["btn-wrapper"]}> <section className={styles["btn-wrapper"]}>
<Button variant="secondary" size="sm"> <Button variant="secondary" size="sm">
Small Small
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
height: 12px; height: 12px;
width: 100%; width: 100%;
font-size: 15px; font-size: 15px;
color: black; color: var(--primary-text-color);
background-color: var(--secondary-bg-color); background-color: var(--secondary-bg-color);
padding: 1.1rem 0; padding: 1.1rem 0;
font-family: "Inter-Medium"; font-family: "Inter-Medium";
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
} }
.input::placeholder { .input::placeholder {
color: rgba(128, 128, 128, 0.605); color: var(--secondary-text-color);
} }
.label { .label {
......
import Input from "./Input"; import Input from "./Input";
import { useState } from "react";
export default { export default {
title: "Components/Base/Input", title: "Components/Base/Input",
component: Input, component: Input,
tags: ["autodocs"], tags: ["autodocs"],
argTypes: { argTypes: {
onChange: { action: "On Input Change" }, onEnter: { action: "Entered Value:: " },
}, },
}; };
export const Default = { export const Default = (args: any) => {
args: { const [value, setValue] = useState("");
placeholder: "Discover news, articles and more..", return (
value: "", <Input
error: false, {...args}
}, value={value}
placeholder="Discover news, articles and more..."
onChange={(e) => setValue(e.target.value)}
onClear={() => setValue("")}
/>
);
}; };
...@@ -7,6 +7,7 @@ type InputProps = { ...@@ -7,6 +7,7 @@ type InputProps = {
label?: string; label?: string;
error?: boolean; error?: boolean;
onClear?: () => void; onClear?: () => void;
onEnter?: (value: string) => void;
} & React.InputHTMLAttributes<HTMLInputElement>; } & React.InputHTMLAttributes<HTMLInputElement>;
export default function Input({ export default function Input({
...@@ -14,8 +15,15 @@ export default function Input({ ...@@ -14,8 +15,15 @@ export default function Input({
onClear, onClear,
value, value,
error, error,
onEnter,
...props ...props
}: InputProps) { }: InputProps) {
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") {
console.log("Entered value:", value);
onEnter?.(value as string);
}
};
return ( return (
<> <>
{label && <div className={styles.label}>{label}</div>} {label && <div className={styles.label}>{label}</div>}
...@@ -56,6 +64,7 @@ export default function Input({ ...@@ -56,6 +64,7 @@ export default function Input({
value != "" ? styles["input-spl"] : styles["input-style"] value != "" ? styles["input-spl"] : styles["input-style"]
}`} }`}
value={value} value={value}
onKeyDown={handleKeyDown}
name="input" name="input"
{...props} {...props}
/> />
......
...@@ -9,6 +9,9 @@ ...@@ -9,6 +9,9 @@
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
padding: 1rem 0; padding: 1rem 0;
position: sticky;
top: 0;
scroll-behavior: smooth;
} }
.input-container { .input-container {
......
...@@ -6,7 +6,8 @@ import styles from "./Header.module.css"; ...@@ -6,7 +6,8 @@ import styles from "./Header.module.css";
import Image from "next/image"; import Image from "next/image";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
export default function Header() { export default function Header() {
const [isDark, setIsDark] = useState("light-theme"); const [isDark, setIsDark] = useState("");
const [searchValue, setSearchValue] = useState("");
const handleThemeToggle = () => { const handleThemeToggle = () => {
setIsDark((prev) => { setIsDark((prev) => {
...@@ -19,21 +20,31 @@ export default function Header() { ...@@ -19,21 +20,31 @@ export default function Header() {
}); });
}; };
useEffect(() => { const handleInputChange = (e: any) => {
console.log("triggered"); setSearchValue(e.target.value);
}, [isDark]); };
const handleSearchEnter = (e: string) => {
console.log(e);
};
return ( return (
<header className={styles["header-wrapper"]}> <header className={styles["header-wrapper"]}>
<div className={styles.headerTitle}>NewsBlog</div> <div className={styles.headerTitle}>NewsBlog</div>
<div className={styles["input-container"]}> <div className={styles["input-container"]}>
<Input placeholder={"Discover news, articles and more..."} value="" /> <Input
placeholder={"Discover news, articles and more..."}
value={searchValue}
onClear={() => setSearchValue("")}
onChange={handleInputChange}
onEnter={handleSearchEnter}
/>
</div> </div>
<div className={styles["theme-switcher"]} onClick={handleThemeToggle}> <div className={styles["theme-switcher"]} onClick={handleThemeToggle}>
{isDark == "dark-theme" ? ( {isDark == "dark-theme" ? (
<Image src={themeLogo} alt="image" width={25} /> <Image src={lightTheme} alt="image" width={25} />
) : ( ) : (
<Image src={lightTheme} alt="theme-img" width={25} /> <Image src={themeLogo} alt="theme-img" width={25} />
)} )}
</div> </div>
</header> </header>
......
...@@ -3,9 +3,10 @@ ...@@ -3,9 +3,10 @@
justify-content: center; justify-content: center;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
margin-top: 20px;
flex-wrap: wrap; flex-wrap: wrap;
font-family: "Inter-Medium"; font-family: "Inter-Medium";
background-color: var(--secondary-bg-color);
padding-bottom: 2rem;
} }
.button { .button {
...@@ -15,6 +16,7 @@ ...@@ -15,6 +16,7 @@
color: #333; color: #333;
text-decoration: none; text-decoration: none;
font-size: 14px; font-size: 14px;
font-family: "Inter-Bold";
transition: background-color 0.2s ease; transition: background-color 0.2s ease;
background: white; background: white;
} }
......
...@@ -55,26 +55,28 @@ export default function Pagination({ ...@@ -55,26 +55,28 @@ export default function Pagination({
return ( return (
<div className={styles.wrapper}> <div className={styles.wrapper}>
{currentPage > 1 && ( {currentPage > 1 && (
<button <Button
variant="primary"
size="md"
onClick={() => onPageChange(currentPage - 1)} onClick={() => onPageChange(currentPage - 1)}
className={styles.button}
> >
« Prev « Prev
</button> </Button>
)} )}
{pages.map((page, index) => { {pages.map((page, index) => {
if (page === "prevDots" || page === "nextDots") { if (page === "prevDots" || page === "nextDots") {
return ( return (
<button <Button
variant="primary"
size="md"
key={`dots-${index}`} key={`dots-${index}`}
className={styles.dots}
onClick={() => onClick={() =>
handleDotsClick(page === "prevDots" ? "prev" : "next") handleDotsClick(page === "prevDots" ? "prev" : "next")
} }
> >
... ...
</button> </Button>
); );
} }
...@@ -82,7 +84,7 @@ export default function Pagination({ ...@@ -82,7 +84,7 @@ export default function Pagination({
<Button <Button
key={`page-${page}`} key={`page-${page}`}
variant="primary" variant="primary"
size="sm" size="md"
active={currentPage === page} active={currentPage === page}
onClick={() => onPageChange(page)} onClick={() => onPageChange(page)}
> >
...@@ -92,12 +94,13 @@ export default function Pagination({ ...@@ -92,12 +94,13 @@ export default function Pagination({
})} })}
{currentPage < totalPages && ( {currentPage < totalPages && (
<button <Button
variant="primary"
size="md"
onClick={() => onPageChange(currentPage + 1)} onClick={() => onPageChange(currentPage + 1)}
className={styles.button}
> >
Next » Next »
</button> </Button>
)} )}
</div> </div>
); );
......
.card { .card {
width: 300px; width: 350px;
border-radius: 10px; border-radius: 10px;
background-color: var(--primary-bg-color); background-color: var(--primary-bg-color);
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px; box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;
...@@ -22,11 +22,23 @@ ...@@ -22,11 +22,23 @@
} }
.card-title { .card-title {
color: var(--primary-text-color); color: var(--primary-text-color);
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-clamp: 2;
text-overflow: ellipsis;
overflow: hidden;
} }
.card-description { .card-description {
color: var(--secondary-text-color); color: var(--secondary-text-color);
font-size: 18px; font-size: 18px;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-clamp: 2;
text-overflow: ellipsis;
overflow: hidden;
} }
.card-footer { .card-footer {
...@@ -37,7 +49,7 @@ ...@@ -37,7 +49,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 1rem; gap: 1rem;
padding: 1rem 0; padding-bottom: 1rem;
} }
.author-name { .author-name {
...@@ -49,15 +61,21 @@ ...@@ -49,15 +61,21 @@
} }
.post-info { .post-info {
display: flex; display: flex;
align-items: center;
gap: 1rem; gap: 1rem;
font-family: "Inter-Regular"; font-family: "Inter-Regular";
color: rgba(128, 128, 128, 0.53); color: rgba(128, 128, 128, 0.53);
color: var(--secondary-text-color); color: var(--secondary-text-color);
font-size: 14px; font-size: 14px;
padding: 2px 0; padding: 2px 0;
} }
.readtimeWrapper {
display: flex;
align-items: center;
gap: 3px;
}
.author-avatar { .author-avatar {
border-radius: 50%; border-radius: 50%;
} }
...@@ -4,8 +4,19 @@ export default { ...@@ -4,8 +4,19 @@ export default {
title: "Components/TopLevel/CardList/Card", title: "Components/TopLevel/CardList/Card",
tags: ["autodocs"], tags: ["autodocs"],
component: Card, component: Card,
argTypes: {},
}; };
export const Default = { export const Default = {
args: {}, args: {
cardTitle:
"Lorem ipsum dolor adipiscing amet Lorem ipsum dolor adipiscing amet ",
cardDescription: "Lorem ipsum dolor adipiscing amet, consectetur sit .",
author: {
postedDate: "July 20, 2025.",
authorName: "Abdul Rahman ",
readTime: "1 min",
},
img: "https://placehold.co/350x200",
},
}; };
import styles from "./Card.module.css"; import styles from "./Card.module.css";
function Card({ img, cardTitle, cardDescription, author }: any) { import clock from "../../../../../public/imgaes/clock.svg";
import Image from "next/image";
function Card({
imgUrl,
cardTitle,
cardDescription,
authorName,
postedDate,
readTime,
}: any) {
console.log(imgUrl, "imgUrl");
return ( return (
<article className={styles.card}> <article className={styles.card}>
<img <img
className={styles["card-avatar"]} className={styles["card-avatar"]}
src="https://picsum.photos/300/200" src={`http://localhost:1337${imgUrl}`}
alt="Author photo" alt="Author photo"
/> />
<section className={styles["card-content"]}> <section className={styles["card-content"]}>
<h3 className={styles["card-title"]}> <h3 className={styles["card-title"]}>{cardTitle}</h3>
Lorem ipsum dolor sit amet, consectetur dolor amet <p className={styles["card-description"]}>{cardDescription}</p>
</h3>
<p className={styles["card-description"]}>
Lorem ipsum dolor adipiscing amet, consectetur sit .
</p>
</section> </section>
<footer className={styles["card-footer"]}> <footer className={styles["card-footer"]}>
<div className={styles["author-details"]}> <div className={styles["author-details"]}>
<div> <div>
<img <img
src="https://picsum.photos/50/50" src="https://picsum.photos/55/55"
alt="Author photo" alt="Author photo"
className={styles["author-avatar"]} className={styles["author-avatar"]}
/> />
</div> </div>
<div className="author-info"> <div className="author-info">
<div className={styles["author-name"]}>Syed Abdul Rahman</div> <div className={styles["author-name"]}>{authorName}</div>
<div className={styles["post-info"]}> <div className={styles["post-info"]}>
<div>July 13, 2020</div> <div>{postedDate}.</div>
<div>1 min</div> <div className={styles.readtimeWrapper}>
<Image width={20} src={clock} alt="img" />
{readTime} min
</div>
</div> </div>
</div> </div>
</div> </div>
......
.wrapperContainer { .wrapperContainer {
display: grid; display: grid;
grid-template-columns: repeat(3, 300px); grid-template-columns: repeat(3, 350px);
column-gap: 1rem; row-gap: 2rem;
row-gap: 1rem; column-gap: 2rem;
justify-content: center;
box-sizing: border-box;
background-color: var(--secondary-bg-color);
padding: 2rem 0;
} }
"use client";
import { Fragment } from "react";
import Card from "../Card/Card"; import Card from "../Card/Card";
import styles from "./CardWrapper.module.css"; import styles from "./CardWrapper.module.css";
const data = [ const data = [
{ {
id: 1, id: 1,
img: "https://placehold.co/300x200", img: "https://picsum.photos/350/300",
title: "Lorem ipsum dolor", title: "Lorem ipsum dolor",
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
author: { author: {
name: "John Doe", authorName: "John Doe",
postedDate: "12/07/2025", postedDate: "July 20, 2025",
readTime: "2", readTime: "2",
}, },
}, },
{ {
id: 2, id: 2,
img: "https://placehold.co/300x200", img: "https://picsum.photos/350/300",
title: "Understanding React Hooks", title: "Understanding React Hooks",
content: content:
"Hooks let you use state and other React features without writing a class.", "Hooks let you use state and other React features without writing a class.",
author: { author: {
name: "Jane Smith", authorName: "Jane Smith",
postedDate: "14/07/2025", postedDate: "July 20, 2025",
readTime: "4", readTime: "4",
}, },
}, },
{ {
id: 3, id: 3,
img: "https://placehold.co/300x200", img: "https://picsum.photos/350/300",
title: "Mastering JavaScript Closures", title: "Mastering JavaScript Closures",
content: content:
"Closures are a fundamental concept that every JavaScript developer should know.", "Closures are a fundamental concept that every JavaScript developer should know.",
author: { author: {
name: "Alex Johnson", authorName: "Alex Johnson",
postedDate: "16/07/2025", postedDate: "July 20, 2025",
readTime: "3", readTime: "3",
}, },
}, },
{ {
id: 4, id: 4,
img: "https://placehold.co/300x200", img: "https://picsum.photos/350/300",
title: "CSS Grid vs Flexbox", title: "CSS Grid vs Flexbox",
content: content:
"Both CSS Grid and Flexbox are powerful layout systems. Learn when to use each.", "Both CSS Grid and Flexbox are powerful layout systems. Learn when to use each.",
author: { author: {
name: "Nina Brown", authorName: "Nina Brown",
postedDate: "18/07/2025", postedDate: "July 20, 2025",
readTime: "5", readTime: "5",
}, },
}, },
{ {
id: 5, id: 5,
img: "https://placehold.co/300x200", img: "https://picsum.photos/350/300",
title: "Building Accessible Web Apps", title: "Building Accessible Web Apps",
content: content:
"Accessibility should be a key focus when building modern web applications.", "Accessibility should be a key focus when building modern web applications.",
author: { author: {
name: "Mohammed Ali", authorName: "Mohammed Ali",
postedDate: "20/07/2025", postedDate: "July 20, 2025",
readTime: "6",
},
},
{
id: 6,
img: "https://picsum.photos/350/300",
title: "Building Accessible Web Apps",
content:
"Accessibility should be a key focus when building modern web applications.",
author: {
authorName: "Mohammed Ali",
postedDate: "July 20, 2025",
readTime: "6", readTime: "6",
}, },
}, },
]; ];
function CardWrapper() { function CardWrapper({ cardData }: any) {
return ( return (
<div className={styles.wrapperContainer}> <div className={styles.wrapperContainer}>
{data.map((ele) => ( {cardData?.map((ele: any) => (
<> <Fragment key={ele.id}>
<Card /> <Card
</> cardTitle={ele.Title}
cardDescription={ele.Description}
authorName={ele.Author}
imgUrl={ele.Image.url}
postedDate={ele.PostedOn}
readTime={ele.ReadingTime}
/>
</Fragment>
))} ))}
</div> </div>
); );
......
import axios from "axios";
const axiosInstance = axios.create({
baseURL: `${process.env.NEXT_PUBLIC_API_URL}api`,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer 8e32297f4b630b69c5446e36e93144e0b3e12827a84252c6c4e6b08d869f817db9b0f7e5c03b6b0553210ac0efe4f7b68bb9f2c3e784e2485794af05087a81f792bf723af2bab3400c5716b478c95c9b8ac0f2a9f3bf836074d8d48cbfeb2f21d03bab93c6f00d846ae7b116953bff27fb09e4cd79febaf2f1bdd421ed7b9417`
},
});
export const getBlogPosts = async () => {
const url = "blog-posts?populate=Image";
try {
const response = await Methods.getData(url);
return response.data;
} catch (error: any) {
throw error?.response?.data || error;
}
}
const Methods = {
getData: async(url:string)=> {
try {
const response = await axiosInstance.get(url);
return response.data;
} catch (error: any) {
throw error?.response?.data || error;
}
},
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment