Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
B
blog-app
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Syed Abdul Rahman
blog-app
Commits
2998de23
Commit
2998de23
authored
Jul 02, 2025
by
Syed Abdul Rahman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dark theme implemented
parent
16708e12
Show whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
338 additions
and
105 deletions
+338
-105
preview.ts
.storybook/preview.ts
+4
-5
package-lock.json
package-lock.json
+81
-16
package.json
package.json
+1
-0
clear-icon.svg
public/imgaes/clear-icon.svg
+3
-2
clock.svg
public/imgaes/clock.svg
+8
-0
globals.css
src/app/globals.css
+3
-0
page.tsx
src/app/page.tsx
+33
-4
Button.module.css
src/components/Base/Button/Button.module.css
+6
-6
Button.stories.tsx
src/components/Base/Button/Button.stories.tsx
+5
-5
Input.module.css
src/components/Base/Input/Input.module.css
+2
-2
Input.stories.tsx
src/components/Base/Input/Input.stories.tsx
+13
-8
Input.tsx
src/components/Base/Input/Input.tsx
+9
-0
Header.module.css
src/components/Layout/Header/Header.module.css
+3
-0
Header.tsx
src/components/Layout/Header/Header.tsx
+18
-7
Pagination.module.css
src/components/Shared/Pagination/Pagination.module.css
+3
-1
Pagination.tsx
src/components/Shared/Pagination/Pagination.tsx
+13
-10
Card.module.css
src/components/TopLevel/CardList/Card/Card.module.css
+21
-3
Card.stories.tsx
src/components/TopLevel/CardList/Card/Card.stories.tsx
+12
-1
Card.tsx
src/components/TopLevel/CardList/Card/Card.tsx
+21
-12
CardWrapper.module.css
...ents/TopLevel/CardList/CardWrapper/CardWrapper.module.css
+7
-3
CardWrapper.tsx
src/components/TopLevel/CardList/CardWrapper/CardWrapper.tsx
+41
-20
Api.ts
src/lib/Api.ts
+31
-0
No files found.
.storybook/preview.ts
View file @
2998de23
...
...
@@ -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
},
[
theme
])
console
.
log
(
"happening"
)
},
[
theme
])
return
Story
()
}
...
...
@@ -47,7 +46,7 @@ const preview: Preview = {
decorators
:
[
ThemeDecorator
],
initialGlobals
:
{
backgrounds
:
{
value
:
'
#ffe788
'
},
backgrounds
:
{
value
:
'
white
'
},
},
}
...
...
package-lock.json
View file @
2998de23
...
...
@@ -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"
,
...
...
package.json
View file @
2998de23
...
...
@@ -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"
...
...
public/imgaes/clear-icon.svg
View file @
2998de23
<!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=
"64
px"
viewBox=
"0 0 24 24"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<svg
width=
"
800px"
height=
"800
px"
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=
"#0
00000"
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=
"#9
69696"
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
...
...
public/imgaes/clock.svg
0 → 100644
View file @
2998de23
<!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
src/app/globals.css
View file @
2998de23
...
...
@@ -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
;
}
src/app/page.tsx
View file @
2998de23
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
}
/>
</>
);
}
src/components/Base/Button/Button.module.css
View file @
2998de23
...
...
@@ -7,9 +7,9 @@
.button
{
border
:
0
;
font-family
:
"Inter-
Medium
"
;
font-family
:
"Inter-
Bold
"
;
cursor
:
pointer
;
border-radius
:
1
0
px
;
border-radius
:
1
2
px
;
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.
2
rem
;
padding
:
1rem
2.
3
rem
;
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
;
}
...
...
src/components/Base/Button/Button.stories.tsx
View file @
2998de23
...
...
@@ -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
...
...
src/components/Base/Input/Input.module.css
View file @
2998de23
...
...
@@ -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
{
...
...
src/components/Base/Input/Input.stories.tsx
View file @
2998de23
import
Input
from
"./Input"
;
import
{
useState
}
from
"react"
;
export
default
{
title
:
"Components/Base/Input"
,
component
:
Input
,
tags
:
[
"autodocs"
],
argTypes
:
{
on
Change
:
{
action
:
"On Input Change
"
},
on
Enter
:
{
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
(
""
)
}
/>
);
};
src/components/Base/Input/Input.tsx
View file @
2998de23
...
...
@@ -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
}
/>
...
...
src/components/Layout/Header/Header.module.css
View file @
2998de23
...
...
@@ -9,6 +9,9 @@
box-sizing
:
border-box
;
width
:
100%
;
padding
:
1rem
0
;
position
:
sticky
;
top
:
0
;
scroll-behavior
:
smooth
;
}
.input-container
{
...
...
src/components/Layout/Header/Header.tsx
View file @
2998de23
...
...
@@ -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
>
...
...
src/components/Shared/Pagination/Pagination.module.css
View file @
2998de23
...
...
@@ -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
;
}
...
...
src/components/Shared/Pagination/Pagination.tsx
View file @
2998de23
...
...
@@ -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
</
b
utton
>
</
B
utton
>
)
}
{
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"
)
}
>
...
</
b
utton
>
</
B
utton
>
);
}
...
...
@@ -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 »
</
b
utton
>
</
B
utton
>
)
}
</
div
>
);
...
...
src/components/TopLevel/CardList/Card/Card.module.css
View file @
2998de23
.card
{
width
:
3
0
0px
;
width
:
3
5
0px
;
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%
;
}
src/components/TopLevel/CardList/Card/Card.stories.tsx
View file @
2998de23
...
...
@@ -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"
,
},
};
src/components/TopLevel/CardList/Card/Card.tsx
View file @
2998de23
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/5
0/50
"
src=
"https://picsum.photos/5
5/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
>
...
...
src/components/TopLevel/CardList/CardWrapper/CardWrapper.module.css
View file @
2998de23
.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
;
}
src/components/TopLevel/CardList/CardWrapper/CardWrapper.tsx
View file @
2998de23
"use client"
;
import
{
Fragment
}
from
"react"
;
import
Card
from
"../Card/Card"
;
import
styles
from
"./CardWrapper.module.css"
;
const
data
=
[
{
id
:
1
,
img
:
"https://p
lacehold.co/300x2
00"
,
img
:
"https://p
icsum.photos/350/3
00"
,
title
:
"Lorem ipsum dolor"
,
content
:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit."
,
author
:
{
n
ame
:
"John Doe"
,
postedDate
:
"
12/07/
2025"
,
authorN
ame
:
"John Doe"
,
postedDate
:
"
July 20,
2025"
,
readTime
:
"2"
,
},
},
{
id
:
2
,
img
:
"https://p
lacehold.co/300x2
00"
,
img
:
"https://p
icsum.photos/350/3
00"
,
title
:
"Understanding React Hooks"
,
content
:
"Hooks let you use state and other React features without writing a class."
,
author
:
{
n
ame
:
"Jane Smith"
,
postedDate
:
"
14/07/
2025"
,
authorN
ame
:
"Jane Smith"
,
postedDate
:
"
July 20,
2025"
,
readTime
:
"4"
,
},
},
{
id
:
3
,
img
:
"https://p
lacehold.co/300x2
00"
,
img
:
"https://p
icsum.photos/350/3
00"
,
title
:
"Mastering JavaScript Closures"
,
content
:
"Closures are a fundamental concept that every JavaScript developer should know."
,
author
:
{
n
ame
:
"Alex Johnson"
,
postedDate
:
"
16/07/
2025"
,
authorN
ame
:
"Alex Johnson"
,
postedDate
:
"
July 20,
2025"
,
readTime
:
"3"
,
},
},
{
id
:
4
,
img
:
"https://p
lacehold.co/300x2
00"
,
img
:
"https://p
icsum.photos/350/3
00"
,
title
:
"CSS Grid vs Flexbox"
,
content
:
"Both CSS Grid and Flexbox are powerful layout systems. Learn when to use each."
,
author
:
{
n
ame
:
"Nina Brown"
,
postedDate
:
"
18/07/
2025"
,
authorN
ame
:
"Nina Brown"
,
postedDate
:
"
July 20,
2025"
,
readTime
:
"5"
,
},
},
{
id
:
5
,
img
:
"https://p
lacehold.co/300x2
00"
,
img
:
"https://p
icsum.photos/350/3
00"
,
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
>
);
...
...
src/lib/Api.ts
View file @
2998de23
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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment