Refactor card components for improved styling and icon updates

This commit is contained in:
Ariful Alam 2025-07-06 17:12:37 +06:00
parent 3d42c1fc21
commit 9c09a9d91e
6 changed files with 132 additions and 112 deletions

View File

@ -1,6 +1,6 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import LazyImage from '../lazy-image'; import LazyImage from '../lazy-image';
import { AiOutlineContainer } from 'react-icons/ai'; import { PiNewspaper } from 'react-icons/pi';
import { getDevPost, getMediumPost } from '@arifszn/blog-js'; import { getDevPost, getMediumPost } from '@arifszn/blog-js';
import { formatDistance } from 'date-fns'; import { formatDistance } from 'date-fns';
import { SanitizedBlog } from '../../interfaces/sanitized-config'; import { SanitizedBlog } from '../../interfaces/sanitized-config';
@ -38,7 +38,7 @@ const BlogCard = ({
const array = []; const array = [];
for (let index = 0; index < blog.limit; index++) { for (let index = 0; index < blog.limit; index++) {
array.push( array.push(
<div className="card shadow-lg card-sm bg-base-100" key={index}> <div className="card shadow-md card-sm bg-base-100" key={index}>
<div className="p-8 h-full w-full"> <div className="p-8 h-full w-full">
<div className="flex items-center flex-col md:flex-row"> <div className="flex items-center flex-col md:flex-row">
<div className="avatar mb-5 md:mb-0"> <div className="avatar mb-5 md:mb-0">
@ -95,7 +95,7 @@ const BlogCard = ({
return articles && articles.length ? ( return articles && articles.length ? (
articles.slice(0, blog.limit).map((article, index) => ( articles.slice(0, blog.limit).map((article, index) => (
<a <a
className="card shadow-lg card-sm bg-base-100 cursor-pointer" className="card shadow-md card-sm bg-base-100 cursor-pointer"
key={index} key={index}
href={article.link} href={article.link}
onClick={(e) => { onClick={(e) => {
@ -162,7 +162,7 @@ const BlogCard = ({
)) ))
) : ( ) : (
<div className="text-center mb-6"> <div className="text-center mb-6">
<AiOutlineContainer className="mx-auto h-12 w-12 opacity-30" /> <PiNewspaper className="mx-auto h-12 w-12 opacity-30" />
<p className="mt-1 text-sm opacity-50 text-base-content"> <p className="mt-1 text-sm opacity-50 text-base-content">
No recent post No recent post
</p> </p>
@ -172,34 +172,38 @@ const BlogCard = ({
return ( return (
<div className="col-span-1 lg:col-span-2"> <div className="col-span-1 lg:col-span-2">
<div className="grid grid-cols-2 gap-6"> <div className="card bg-base-200 shadow-xl border border-base-300">
<div className="col-span-2"> <div className="card-body p-8">
<div <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-8">
className={`card card-sm bg-base-100 ${ <div className="flex items-center space-x-3">
loading || (articles && articles.length) {loading ? (
? 'shadow-sm bg-opacity-40' skeleton({
: 'shadow-lg' widthCls: 'w-12',
}`} heightCls: 'h-12',
> className: 'rounded-xl',
<div className="card-body"> })
<div className="mx-3 mb-2"> ) : (
<h5 className="card-title"> <div className="flex items-center justify-center w-12 h-12 bg-primary/10 rounded-xl">
{loading ? ( <PiNewspaper className="text-2xl" />
skeleton({ widthCls: 'w-28', heightCls: 'h-8' })
) : (
<span className="text-base-content opacity-70">
My Articles
</span>
)}
</h5>
</div>
<div className="col-span-2">
<div className="grid grid-cols-1 gap-6">
{loading || !articles ? renderSkeleton() : renderArticles()}
</div> </div>
)}
<div className="min-w-0 flex-1">
<h3 className="text-base sm:text-lg font-bold text-base-content truncate">
{loading
? skeleton({ widthCls: 'w-28', heightCls: 'h-8' })
: 'My Articles'}
</h3>
<p className="text-base-content/60 text-xs sm:text-sm mt-1 truncate">
{loading
? skeleton({ widthCls: 'w-32', heightCls: 'h-4' })
: 'Recent posts'}
</p>
</div> </div>
</div> </div>
</div> </div>
<div className="grid grid-cols-1 gap-6">
{loading || !articles ? renderSkeleton() : renderArticles()}
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,5 +1,6 @@
import { Fragment } from 'react'; import { Fragment } from 'react';
import LazyImage from '../lazy-image'; import LazyImage from '../lazy-image';
import { MdOpenInNew } from 'react-icons/md';
import { ga, skeleton } from '../../utils'; import { ga, skeleton } from '../../utils';
import { SanitizedExternalProject } from '../../interfaces/sanitized-config'; import { SanitizedExternalProject } from '../../interfaces/sanitized-config';
@ -18,7 +19,7 @@ const ExternalProjectCard = ({
const array = []; const array = [];
for (let index = 0; index < externalProjects.length; index++) { for (let index = 0; index < externalProjects.length; index++) {
array.push( array.push(
<div className="card shadow-lg card-sm bg-base-100" key={index}> <div className="card shadow-md card-sm bg-base-100" key={index}>
<div className="p-8 h-full w-full"> <div className="p-8 h-full w-full">
<div className="flex items-center flex-col"> <div className="flex items-center flex-col">
<div className="w-full"> <div className="w-full">
@ -69,7 +70,7 @@ const ExternalProjectCard = ({
const renderExternalProjects = () => { const renderExternalProjects = () => {
return externalProjects.map((item, index) => ( return externalProjects.map((item, index) => (
<a <a
className="card shadow-lg card-sm bg-base-100 cursor-pointer" className="card shadow-md card-sm bg-base-100 cursor-pointer"
key={index} key={index}
href={item.link} href={item.link}
onClick={(e) => { onClick={(e) => {
@ -126,28 +127,38 @@ const ExternalProjectCard = ({
return ( return (
<Fragment> <Fragment>
<div className="col-span-1 lg:col-span-2"> <div className="col-span-1 lg:col-span-2">
<div className="grid grid-cols-2 gap-6"> <div className="card bg-base-200 shadow-xl border border-base-300">
<div className="col-span-2"> <div className="card-body p-8">
<div className="card card-sm bg-base-100 shadow-sm bg-opacity-40"> <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-8">
<div className="card-body"> <div className="flex items-center space-x-3">
<div className="mx-3 flex items-center justify-between mb-2"> {loading ? (
<h5 className="card-title"> skeleton({
{loading ? ( widthCls: 'w-12',
skeleton({ widthCls: 'w-40', heightCls: 'h-8' }) heightCls: 'h-12',
) : ( className: 'rounded-xl',
<span className="text-base-content opacity-70"> })
{header} ) : (
</span> <div className="flex items-center justify-center w-12 h-12 bg-primary/10 rounded-xl">
)} <MdOpenInNew className="text-2xl" />
</h5>
</div>
<div className="col-span-2">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{loading ? renderSkeleton() : renderExternalProjects()}
</div> </div>
)}
<div className="min-w-0 flex-1">
<h3 className="text-base sm:text-lg font-bold text-base-content truncate">
{loading
? skeleton({ widthCls: 'w-40', heightCls: 'h-8' })
: header}
</h3>
<p className="text-base-content/60 text-xs sm:text-sm mt-1 truncate">
{loading
? skeleton({ widthCls: 'w-32', heightCls: 'h-4' })
: `Showcasing ${externalProjects.length} external projects`}
</p>
</div> </div>
</div> </div>
</div> </div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{loading ? renderSkeleton() : renderExternalProjects()}
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
import { Fragment } from 'react'; import { Fragment } from 'react';
import { AiOutlineFork, AiOutlineStar } from 'react-icons/ai'; import { AiOutlineFork, AiOutlineStar, AiOutlineGithub } from 'react-icons/ai';
import { MdInsertLink } from 'react-icons/md'; import { MdInsertLink } from 'react-icons/md';
import { ga, getLanguageColor, skeleton } from '../../utils'; import { ga, getLanguageColor, skeleton } from '../../utils';
import { GithubProject } from '../../interfaces/github-project'; import { GithubProject } from '../../interfaces/github-project';
@ -9,14 +9,12 @@ const GithubProjectCard = ({
githubProjects, githubProjects,
loading, loading,
limit, limit,
username,
googleAnalyticsId, googleAnalyticsId,
}: { }: {
header: string; header: string;
githubProjects: GithubProject[]; githubProjects: GithubProject[];
loading: boolean; loading: boolean;
limit: number; limit: number;
username: string;
googleAnalyticsId?: string; googleAnalyticsId?: string;
}) => { }) => {
if (!loading && githubProjects.length === 0) { if (!loading && githubProjects.length === 0) {
@ -27,7 +25,7 @@ const GithubProjectCard = ({
const array = []; const array = [];
for (let index = 0; index < limit; index++) { for (let index = 0; index < limit; index++) {
array.push( array.push(
<div className="card shadow-lg card-sm bg-base-100" key={index}> <div className="card shadow-md card-sm bg-base-100" key={index}>
<div className="flex justify-between flex-col p-8 h-full w-full"> <div className="flex justify-between flex-col p-8 h-full w-full">
<div> <div>
<div className="flex items-center"> <div className="flex items-center">
@ -76,7 +74,7 @@ const GithubProjectCard = ({
const renderProjects = () => { const renderProjects = () => {
return githubProjects.map((item, index) => ( return githubProjects.map((item, index) => (
<a <a
className="card shadow-lg card-sm bg-base-100 cursor-pointer" className="card shadow-md card-sm bg-base-100 cursor-pointer"
href={item.html_url} href={item.html_url}
key={index} key={index}
onClick={(e) => { onClick={(e) => {
@ -84,9 +82,7 @@ const GithubProjectCard = ({
try { try {
if (googleAnalyticsId) { if (googleAnalyticsId) {
ga.event('Click project', { ga.event('Click project', { project: item.name });
project: item.name,
});
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -136,40 +132,41 @@ const GithubProjectCard = ({
return ( return (
<Fragment> <Fragment>
<div className="col-span-1 lg:col-span-2"> <div className="col-span-1 lg:col-span-2">
<div className="grid grid-cols-2 gap-6"> <div className="card bg-base-200 shadow-xl border border-base-300">
<div className="col-span-2"> <div className="card-body p-8">
<div className="card card-sm bg-base-100 shadow-sm bg-opacity-40"> {/* Enhanced Header Section */}
<div className="card-body"> <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-8">
<div className="mx-3 flex items-center justify-between mb-2"> <div className="flex items-center space-x-3">
<h5 className="card-title"> {loading ? (
{loading ? ( skeleton({
skeleton({ widthCls: 'w-40', heightCls: 'h-8' }) widthCls: 'w-12',
) : ( heightCls: 'h-12',
<span className="text-base-content opacity-70"> className: 'rounded-xl',
{header} })
</span> ) : (
)} <div className="flex items-center justify-center w-12 h-12 bg-primary/10 rounded-xl">
</h5> <AiOutlineGithub className="text-2xl" />
{loading ? (
skeleton({ widthCls: 'w-10', heightCls: 'h-5' })
) : (
<a
href={`https://github.com/${username}?tab=repositories`}
target="_blank"
rel="noreferrer"
className="text-base-content opacity-50 hover:underline"
>
See All
</a>
)}
</div>
<div className="col-span-2">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{loading ? renderSkeleton() : renderProjects()}
</div> </div>
)}
<div className="min-w-0 flex-1">
<h3 className="text-base sm:text-lg font-bold text-base-content truncate">
{loading
? skeleton({ widthCls: 'w-48', heightCls: 'h-8' })
: header}
</h3>
<p className="text-base-content/60 text-xs sm:text-sm mt-1 truncate">
{loading
? skeleton({ widthCls: 'w-32', heightCls: 'h-4' })
: `Showcasing ${githubProjects.length} featured repositories`}
</p>
</div> </div>
</div> </div>
</div> </div>
{/* Projects Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{loading ? renderSkeleton() : renderProjects()}
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,4 +1,5 @@
import { Fragment } from 'react'; import { Fragment } from 'react';
import { AiOutlineBook } from 'react-icons/ai';
import { SanitizedPublication } from '../../interfaces/sanitized-config'; import { SanitizedPublication } from '../../interfaces/sanitized-config';
import { skeleton } from '../../utils'; import { skeleton } from '../../utils';
@ -13,7 +14,7 @@ const PublicationCard = ({
const array = []; const array = [];
for (let index = 0; index < publications.length; index++) { for (let index = 0; index < publications.length; index++) {
array.push( array.push(
<div className="card shadow-lg card-sm bg-base-100" key={index}> <div className="card shadow-md card-sm bg-base-100" key={index}>
<div className="p-8 h-full w-full"> <div className="p-8 h-full w-full">
<div className="flex items-center flex-col"> <div className="flex items-center flex-col">
<div className="w-full"> <div className="w-full">
@ -76,7 +77,7 @@ const PublicationCard = ({
const renderPublications = () => { const renderPublications = () => {
return publications.map((item, index) => ( return publications.map((item, index) => (
<a <a
className="card shadow-lg card-sm bg-base-100 cursor-pointer" className="card shadow-md card-sm bg-base-100 cursor-pointer"
key={index} key={index}
href={item.link} href={item.link}
target="_blank" target="_blank"
@ -120,28 +121,38 @@ const PublicationCard = ({
return ( return (
<Fragment> <Fragment>
<div className="col-span-1 lg:col-span-2"> <div className="col-span-1 lg:col-span-2">
<div className="grid grid-cols-2 gap-6"> <div className="card bg-base-200 shadow-xl border border-base-300">
<div className="col-span-2"> <div className="card-body p-8">
<div className="card card-sm bg-base-100 shadow-sm bg-opacity-40"> <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-8">
<div className="card-body"> <div className="flex items-center space-x-3">
<div className="mx-3 flex items-center justify-between mb-2"> {loading ? (
<h5 className="card-title"> skeleton({
{loading ? ( widthCls: 'w-12',
skeleton({ widthCls: 'w-40', heightCls: 'h-8' }) heightCls: 'h-12',
) : ( className: 'rounded-xl',
<span className="text-base-content opacity-70"> })
Publications ) : (
</span> <div className="flex items-center justify-center w-12 h-12 bg-primary/10 rounded-xl">
)} <AiOutlineBook className="text-2xl" />
</h5>
</div>
<div className="col-span-2">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{loading ? renderSkeleton() : renderPublications()}
</div> </div>
)}
<div className="min-w-0 flex-1">
<h3 className="text-base sm:text-lg font-bold text-base-content truncate">
{loading
? skeleton({ widthCls: 'w-40', heightCls: 'h-8' })
: 'Publications'}
</h3>
<p className="text-base-content/60 text-xs sm:text-sm mt-1 truncate">
{loading
? skeleton({ widthCls: 'w-32', heightCls: 'h-4' })
: `Showcasing ${publications.length} publications`}
</p>
</div> </div>
</div> </div>
</div> </div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{loading ? renderSkeleton() : renderPublications()}
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -33,14 +33,11 @@ const SkillCard = ({
</h5> </h5>
</div> </div>
<div className="p-3 flow-root"> <div className="p-3 flow-root">
<div className="-m-1 flex flex-wrap justify-center"> <div className="-m-1 flex flex-wrap justify-center gap-2">
{loading {loading
? renderSkeleton() ? renderSkeleton()
: skills.map((skill, index) => ( : skills.map((skill, index) => (
<div <div key={index} className="badge badge-primary badge-sm">
key={index}
className="m-1 text-xs inline-flex items-center font-bold leading-sm px-3 py-1 badge-primary bg-opacity-90 rounded-full"
>
{skill} {skill}
</div> </div>
))} ))}

View File

@ -65,7 +65,7 @@ const ThemeChanger = ({
<div className="flex-0"> <div className="flex-0">
{loading ? ( {loading ? (
skeleton({ skeleton({
widthCls: 'w-14 md:w-28', widthCls: 'w-12',
heightCls: 'h-10', heightCls: 'h-10',
className: 'mr-6', className: 'mr-6',
}) })