Commit 2998de23 by Syed Abdul Rahman

dark theme implemented

parent 16708e12
......@@ -2,24 +2,23 @@ import type { Preview } from '@storybook/nextjs'
import { useEffect } from 'react'
import '../src/app/fonts.css'
// Decorator to handle theme changes and update HTML attributes
const ThemeDecorator = (Story: any, context: any) => {
const backgroundValue = context.globals.backgrounds?.value
console.log(backgroundValue,"backgroundValue")
// Determine theme based on background value
const theme = backgroundValue === 'dark' ? 'dark-theme' : 'light-theme'
const theme = backgroundValue == 'dark' ? 'dark-theme' : ''
useEffect(() => {
// Update document root attributes
document.documentElement.setAttribute('data-theme', theme)
// Update body attributes
document.body.setAttribute('data-theme', theme)
// document.body.setAttribute('data-theme', theme)
// You can also update specific elements if needed
console.log("happening")
}, [theme])
console.log("happening")
return Story()
}
......@@ -47,7 +46,7 @@ const preview: Preview = {
decorators: [ThemeDecorator],
initialGlobals: {
backgrounds: { value: '#ffe788' },
backgrounds: { value: 'white' },
},
}
......
......@@ -8,6 +8,7 @@
"name": "blog-app",
"version": "0.1.0",
"dependencies": {
"axios": "^1.10.0",
"next": "15.3.4",
"react": "^19.0.0",
"react-dom": "^19.0.0"
......@@ -5216,6 +5217,12 @@
"node": ">= 0.4"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
......@@ -5242,6 +5249,17 @@
"node": ">=4"
}
},
"node_modules/axios": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz",
"integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/axobject-query": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
......@@ -5799,7 +5817,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
......@@ -6071,6 +6088,18 @@
"dev": true,
"license": "MIT"
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/commander": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
......@@ -6542,6 +6571,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/dequal": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
......@@ -6711,7 +6749,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
......@@ -6915,7 +6952,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
......@@ -6925,7 +6961,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
......@@ -6970,7 +7005,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
......@@ -6983,7 +7017,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
......@@ -7768,6 +7801,26 @@
"dev": true,
"license": "ISC"
},
"node_modules/follow-redirects": {
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/for-each": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
......@@ -7832,6 +7885,22 @@
"url": "https://opencollective.com/webpack"
}
},
"node_modules/form-data": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz",
"integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fs-extra": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
......@@ -7880,7 +7949,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
......@@ -7931,7 +7999,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
......@@ -7956,7 +8023,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"dev": true,
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
......@@ -8073,7 +8139,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
......@@ -8152,7 +8217,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
......@@ -8165,7 +8229,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
......@@ -8206,7 +8269,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
......@@ -9323,7 +9385,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
......@@ -9410,7 +9471,6 @@
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.6"
......@@ -9420,7 +9480,6 @@
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
......@@ -10485,6 +10544,12 @@
"react-is": "^16.13.1"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT"
},
"node_modules/public-encrypt": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
......
......@@ -11,6 +11,7 @@
"build-storybook": "storybook build"
},
"dependencies": {
"axios": "^1.10.0",
"next": "15.3.4",
"react": "^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">
<!-- 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_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>
\ 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 @@
--secondary-bg-color: #f8f9fa;
--primary-text-color: #2d3748;
--secondary-text-color: #9d99b3;
--disabled-button-bg: rgba(115, 40, 255, 0.26);
}
[data-theme="dark-theme"] {
......@@ -10,8 +11,10 @@
--secondary-bg-color: #0b0d0e;
--primary-text-color: #e4e4e4;
--secondary-text-color: #8fa2ae;
--disabled-button-bg: rgba(193, 180, 216, 0.516);
}
html,
body {
margin: 0;
}
import Image from "next/image";
import styles from "./page.module.css";
import Header from "@/components/Layout/Header/Header";
"use client";
import CardWrapper from "@/components/TopLevel/CardList/CardWrapper/CardWrapper";
import Pagination from "@/components/Shared/Pagination/Pagination";
import { useEffect, useState } from "react";
import { getBlogPosts } from "@/lib/Api";
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 @@
.button {
border: 0;
font-family: "Inter-Medium";
font-family: "Inter-Bold";
cursor: pointer;
border-radius: 10px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
......@@ -25,7 +25,7 @@
.primary:hover {
color: white;
background-color: rgb(115, 40, 255) !important;
background-color: rgb(115, 101, 243) !important;
}
.secondary {
......@@ -50,13 +50,13 @@
}
.lg {
padding: 1rem 2.2rem;
padding: 1rem 2.3rem;
font-size: 18px;
}
.button-active {
color: white;
background-color: rgb(115, 40, 255);
background-color: rgb(115, 101, 243);
}
.loader {
......@@ -84,7 +84,7 @@
}
.disabled {
background-color: rgba(115, 40, 255, 0.26);
background-color: var(--disabled-button-bg);
color: gray;
pointer-events: none;
}
......
......@@ -10,7 +10,7 @@ export const Primary = {
render: () => {
return (
<>
<h2 style={{ fontFamily: "Inter-Medium", color: "gray" }}>Size</h2>
<h2 style={{ fontFamily: "Inter-Medium", color: "black" }}>Size</h2>
<section className={styles["btn-wrapper"]}>
<Button variant="primary" size="sm">
Small
......@@ -22,7 +22,7 @@ export const Primary = {
Large
</Button>
</section>
<h2 style={{ fontFamily: "Inter-Medium", color: "gray" }}>Loader</h2>
<h2 style={{ fontFamily: "Inter-Medium", color: "black" }}>Loader</h2>
<section className={styles["btn-wrapper"]}>
<Button variant="primary" size="sm" loading={true}>
Button
......@@ -34,7 +34,7 @@ export const Primary = {
Button
</Button>
</section>
<h2 style={{ fontFamily: "Inter-Medium", color: "gray" }}>Disabled</h2>
<h2 style={{ fontFamily: "Inter-Medium", color: "black" }}>Disabled</h2>
<section className={styles["btn-wrapper"]}>
<Button variant="primary" size="sm" disabled={true}>
Button
......@@ -46,7 +46,7 @@ export const Primary = {
Button
</Button>
</section>
<h2 style={{ fontFamily: "Inter-Medium", color: "gray" }}>
<h2 style={{ fontFamily: "Inter-Medium", color: "black" }}>
Loader and Disabled
</h2>
<section className={styles["btn-wrapper"]}>
......@@ -70,7 +70,7 @@ export const Secondary = {
render: () => {
return (
<>
<h2 style={{ fontFamily: "Inter-Medium", color: "gray" }}>Size</h2>
<h2 style={{ fontFamily: "Inter-Medium", color: "black" }}>Size</h2>
<section className={styles["btn-wrapper"]}>
<Button variant="secondary" size="sm">
Small
......
......@@ -13,7 +13,7 @@
height: 12px;
width: 100%;
font-size: 15px;
color: black;
color: var(--primary-text-color);
background-color: var(--secondary-bg-color);
padding: 1.1rem 0;
font-family: "Inter-Medium";
......@@ -26,7 +26,7 @@
}
.input::placeholder {
color: rgba(128, 128, 128, 0.605);
color: var(--secondary-text-color);
}
.label {
......
import Input from "./Input";
import { useState } from "react";
export default {
title: "Components/Base/Input",
component: Input,
tags: ["autodocs"],
argTypes: {
onChange: { action: "On Input Change" },
onEnter: { action: "Entered Value:: " },
},
};
export const Default = {
args: {
placeholder: "Discover news, articles and more..",
value: "",
error: false,
},
export const Default = (args: any) => {
const [value, setValue] = useState("");
return (
<Input
{...args}
value={value}
placeholder="Discover news, articles and more..."
onChange={(e) => setValue(e.target.value)}
onClear={() => setValue("")}
/>
);
};
......@@ -7,6 +7,7 @@ type InputProps = {
label?: string;
error?: boolean;
onClear?: () => void;
onEnter?: (value: string) => void;
} & React.InputHTMLAttributes<HTMLInputElement>;
export default function Input({
......@@ -14,8 +15,15 @@ export default function Input({
onClear,
value,
error,
onEnter,
...props
}: InputProps) {
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") {
console.log("Entered value:", value);
onEnter?.(value as string);
}
};
return (
<>
{label && <div className={styles.label}>{label}</div>}
......@@ -56,6 +64,7 @@ export default function Input({
value != "" ? styles["input-spl"] : styles["input-style"]
}`}
value={value}
onKeyDown={handleKeyDown}
name="input"
{...props}
/>
......
......@@ -9,6 +9,9 @@
box-sizing: border-box;
width: 100%;
padding: 1rem 0;
position: sticky;
top: 0;
scroll-behavior: smooth;
}
.input-container {
......
......@@ -6,7 +6,8 @@ import styles from "./Header.module.css";
import Image from "next/image";
import { useEffect, useState } from "react";
export default function Header() {
const [isDark, setIsDark] = useState("light-theme");
const [isDark, setIsDark] = useState("");
const [searchValue, setSearchValue] = useState("");
const handleThemeToggle = () => {
setIsDark((prev) => {
......@@ -19,21 +20,31 @@ export default function Header() {
});
};
useEffect(() => {
console.log("triggered");
}, [isDark]);
const handleInputChange = (e: any) => {
setSearchValue(e.target.value);
};
const handleSearchEnter = (e: string) => {
console.log(e);
};
return (
<header className={styles["header-wrapper"]}>
<div className={styles.headerTitle}>NewsBlog</div>
<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 className={styles["theme-switcher"]} onClick={handleThemeToggle}>
{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>
</header>
......
......@@ -3,9 +3,10 @@
justify-content: center;
align-items: center;
gap: 8px;
margin-top: 20px;
flex-wrap: wrap;
font-family: "Inter-Medium";
background-color: var(--secondary-bg-color);
padding-bottom: 2rem;
}
.button {
......@@ -15,6 +16,7 @@
color: #333;
text-decoration: none;
font-size: 14px;
font-family: "Inter-Bold";
transition: background-color 0.2s ease;
background: white;
}
......
......@@ -55,26 +55,28 @@ export default function Pagination({
return (
<div className={styles.wrapper}>
{currentPage > 1 && (
<button
<Button
variant="primary"
size="md"
onClick={() => onPageChange(currentPage - 1)}
className={styles.button}
>
« Prev
</button>
</Button>
)}
{pages.map((page, index) => {
if (page === "prevDots" || page === "nextDots") {
return (
<button
<Button
variant="primary"
size="md"
key={`dots-${index}`}
className={styles.dots}
onClick={() =>
handleDotsClick(page === "prevDots" ? "prev" : "next")
}
>
...
</button>
</Button>
);
}
......@@ -82,7 +84,7 @@ export default function Pagination({
<Button
key={`page-${page}`}
variant="primary"
size="sm"
size="md"
active={currentPage === page}
onClick={() => onPageChange(page)}
>
......@@ -92,12 +94,13 @@ export default function Pagination({
})}
{currentPage < totalPages && (
<button
<Button
variant="primary"
size="md"
onClick={() => onPageChange(currentPage + 1)}
className={styles.button}
>
Next »
</button>
</Button>
)}
</div>
);
......
.card {
width: 300px;
width: 350px;
border-radius: 10px;
background-color: var(--primary-bg-color);
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;
......@@ -22,11 +22,23 @@
}
.card-title {
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 {
color: var(--secondary-text-color);
font-size: 18px;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-clamp: 2;
text-overflow: ellipsis;
overflow: hidden;
}
.card-footer {
......@@ -37,7 +49,7 @@
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem 0;
padding-bottom: 1rem;
}
.author-name {
......@@ -49,15 +61,21 @@
}
.post-info {
display: flex;
align-items: center;
gap: 1rem;
font-family: "Inter-Regular";
color: rgba(128, 128, 128, 0.53);
color: var(--secondary-text-color);
font-size: 14px;
padding: 2px 0;
}
.readtimeWrapper {
display: flex;
align-items: center;
gap: 3px;
}
.author-avatar {
border-radius: 50%;
}
......@@ -4,8 +4,19 @@ export default {
title: "Components/TopLevel/CardList/Card",
tags: ["autodocs"],
component: Card,
argTypes: {},
};
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";
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 (
<article className={styles.card}>
<img
className={styles["card-avatar"]}
src="https://picsum.photos/300/200"
src={`http://localhost:1337${imgUrl}`}
alt="Author photo"
/>
<section className={styles["card-content"]}>
<h3 className={styles["card-title"]}>
Lorem ipsum dolor sit amet, consectetur dolor amet
</h3>
<p className={styles["card-description"]}>
Lorem ipsum dolor adipiscing amet, consectetur sit .
</p>
<h3 className={styles["card-title"]}>{cardTitle}</h3>
<p className={styles["card-description"]}>{cardDescription}</p>
</section>
<footer className={styles["card-footer"]}>
<div className={styles["author-details"]}>
<div>
<img
src="https://picsum.photos/50/50"
src="https://picsum.photos/55/55"
alt="Author photo"
className={styles["author-avatar"]}
/>
</div>
<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>July 13, 2020</div>
<div>1 min</div>
<div>{postedDate}.</div>
<div className={styles.readtimeWrapper}>
<Image width={20} src={clock} alt="img" />
{readTime} min
</div>
</div>
</div>
</div>
......
.wrapperContainer {
display: grid;
grid-template-columns: repeat(3, 300px);
column-gap: 1rem;
row-gap: 1rem;
grid-template-columns: repeat(3, 350px);
row-gap: 2rem;
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 styles from "./CardWrapper.module.css";
const data = [
{
id: 1,
img: "https://placehold.co/300x200",
img: "https://picsum.photos/350/300",
title: "Lorem ipsum dolor",
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
author: {
name: "John Doe",
postedDate: "12/07/2025",
authorName: "John Doe",
postedDate: "July 20, 2025",
readTime: "2",
},
},
{
id: 2,
img: "https://placehold.co/300x200",
img: "https://picsum.photos/350/300",
title: "Understanding React Hooks",
content:
"Hooks let you use state and other React features without writing a class.",
author: {
name: "Jane Smith",
postedDate: "14/07/2025",
authorName: "Jane Smith",
postedDate: "July 20, 2025",
readTime: "4",
},
},
{
id: 3,
img: "https://placehold.co/300x200",
img: "https://picsum.photos/350/300",
title: "Mastering JavaScript Closures",
content:
"Closures are a fundamental concept that every JavaScript developer should know.",
author: {
name: "Alex Johnson",
postedDate: "16/07/2025",
authorName: "Alex Johnson",
postedDate: "July 20, 2025",
readTime: "3",
},
},
{
id: 4,
img: "https://placehold.co/300x200",
img: "https://picsum.photos/350/300",
title: "CSS Grid vs Flexbox",
content:
"Both CSS Grid and Flexbox are powerful layout systems. Learn when to use each.",
author: {
name: "Nina Brown",
postedDate: "18/07/2025",
authorName: "Nina Brown",
postedDate: "July 20, 2025",
readTime: "5",
},
},
{
id: 5,
img: "https://placehold.co/300x200",
img: "https://picsum.photos/350/300",
title: "Building Accessible Web Apps",
content:
"Accessibility should be a key focus when building modern web applications.",
author: {
name: "Mohammed Ali",
postedDate: "20/07/2025",
authorName: "Mohammed Ali",
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",
},
},
];
function CardWrapper() {
function CardWrapper({ cardData }: any) {
return (
<div className={styles.wrapperContainer}>
{data.map((ele) => (
<>
<Card />
</>
{cardData?.map((ele: any) => (
<Fragment key={ele.id}>
<Card
cardTitle={ele.Title}
cardDescription={ele.Description}
authorName={ele.Author}
imgUrl={ele.Image.url}
postedDate={ele.PostedOn}
readTime={ele.ReadingTime}
/>
</Fragment>
))}
</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