fix slider post and add skeleton

This commit is contained in:
zahravaziri
2025-07-01 12:25:50 +03:30
parent 21c52a84ed
commit 123df850a8
5 changed files with 99 additions and 19 deletions
@@ -0,0 +1,21 @@
'use client';
interface Props {
count?: number;
}
export default function SliderThumbSkeleton({ count = 3 }: Props) {
return (
<div className="flex gap-4 overflow-hidden">
{Array.from({ length: count }).map((_, i) => (
<div
key={i}
className="flex w-full animate-pulse flex-col gap-4 overflow-hidden rounded-xl bg-white"
>
<div className="aspect-[1.09] w-full bg-gray-200" />
<div className="mx-auto mb-4 h-4 w-3/4 rounded bg-gray-200" />
</div>
))}
</div>
);
}
+1 -1
View File
@@ -17,7 +17,7 @@ const PostThumb = ({ post, locale }: Props) => {
return ( return (
<div <div
key={post.id} key={post.id}
className="group flex flex-col gap-3 overflow-hidden bg-white md:gap-5" className="group flex w-full flex-col gap-3 overflow-hidden bg-white md:gap-5"
> >
<div className="relative aspect-[1.09] w-full overflow-hidden rounded-2xl"> <div className="relative aspect-[1.09] w-full overflow-hidden rounded-2xl">
<Image <Image
@@ -1,14 +1,58 @@
// 'use client';
// import { Swiper, SwiperSlide } from 'swiper/react';
// import { FreeMode } from 'swiper/modules';
// import 'swiper/css';
// import 'swiper/css/free-mode';
// import { IPostThumbResponseData } from '@/app/api/blog/data';
// import { useTranslations } from 'use-intl';
// import routeFactory from '@/assets/constants/routeFactory';
// import { TLocales } from '@/models/layout';
// import PostThumb from './PostThumb';
// interface Props {
// posts: IPostThumbResponseData[];
// locale: TLocales;
// }
// export default function PostsGridViewSlider({ posts, locale }: Props) {
// const t = useTranslations();
// const routes = routeFactory(t, locale);
// return (
// <div className="w-full">
// <Swiper
// modules={[FreeMode]}
// freeMode
// spaceBetween={16}
// breakpoints={{
// 0: { slidesPerView: 1.1 },
// 768: { slidesPerView: Math.min(posts.length, 3), spaceBetween: 24 },
// }}
// className="w-full"
// >
// {posts.map((post) => (
// <SwiperSlide key={post.id} className="w-auto">
// <PostThumb post={post} locale={locale} />
// </SwiperSlide>
// ))}
// </Swiper>
// </div>
// );
// }
'use client'; 'use client';
import { useEffect, useState } from 'react';
import { Swiper, SwiperSlide } from 'swiper/react'; import { Swiper, SwiperSlide } from 'swiper/react';
import { FreeMode } from 'swiper/modules'; import { FreeMode } from 'swiper/modules';
import 'swiper/css'; import 'swiper/css';
import 'swiper/css/free-mode'; import 'swiper/css/free-mode';
import PostThumb from './PostThumb';
import { IPostThumbResponseData } from '@/app/api/blog/data'; import { IPostThumbResponseData } from '@/app/api/blog/data';
import { TLocales } from '@/models/layout';
import { useTranslations } from 'use-intl'; import { useTranslations } from 'use-intl';
import routeFactory from '@/assets/constants/routeFactory'; import routeFactory from '@/assets/constants/routeFactory';
import { TLocales } from '@/models/layout'; import SliderThumbSkeleton from '@/components/layout/sliderSkeleton';
import PostThumb from './PostThumb';
interface Props { interface Props {
posts: IPostThumbResponseData[]; posts: IPostThumbResponseData[];
@@ -16,8 +60,18 @@ interface Props {
} }
export default function PostsGridViewSlider({ posts, locale }: Props) { export default function PostsGridViewSlider({ posts, locale }: Props) {
const [hasMounted, setHasMounted] = useState(false);
const t = useTranslations(); const t = useTranslations();
const routes = routeFactory(t, locale); const routes = routeFactory(t, locale);
useEffect(() => {
setHasMounted(true);
}, []);
if (!hasMounted) {
return <SliderThumbSkeleton count={3} />;
}
return ( return (
<div className="w-full"> <div className="w-full">
<Swiper <Swiper
@@ -26,12 +80,12 @@ export default function PostsGridViewSlider({ posts, locale }: Props) {
spaceBetween={16} spaceBetween={16}
breakpoints={{ breakpoints={{
0: { slidesPerView: 1.1 }, 0: { slidesPerView: 1.1 },
768: { slidesPerView: posts.length, spaceBetween: 24 }, 768: { slidesPerView: Math.min(posts.length, 3), spaceBetween: 24 },
}} }}
className="w-full" className="w-full"
> >
{posts.map((post) => ( {posts.map((post) => (
<SwiperSlide key={post.id}> <SwiperSlide key={post.id} className="w-auto">
<PostThumb post={post} locale={locale} /> <PostThumb post={post} locale={locale} />
</SwiperSlide> </SwiperSlide>
))} ))}
+10 -7
View File
@@ -28,13 +28,16 @@ export default async function HomePageBlog({ locale, className }: Props) {
<h4 className="text-base font-extralight tracking-normal max-lg:hidden"> <h4 className="text-base font-extralight tracking-normal max-lg:hidden">
{t('com_home_blog_description')} {t('com_home_blog_description')}
</h4> </h4>
<Button
link={routes.blog.route()} <div className="flex w-full justify-end">
endIcon="showMore" <Button
className="mt-5" link={routes.blog.route()}
> endIcon="showMore"
{t('com_home_blog_show_more')} className="mt-5"
</Button> >
{t('com_home_blog_show_more')}
</Button>
</div>
</div> </div>
</div> </div>
+9 -7
View File
@@ -29,13 +29,15 @@ export default async function HomePageProjects({ locale }: Props) {
<h4 className="text-base font-extralight tracking-normal max-lg:hidden"> <h4 className="text-base font-extralight tracking-normal max-lg:hidden">
{t('com_home_projects_description')} {t('com_home_projects_description')}
</h4> </h4>
<Button <div className="flex w-full justify-end">
link={routes.projects.route()} <Button
endIcon="showMore" link={routes.projects.route()}
className="mt-5" endIcon="showMore"
> className="mt-5"
{t('com_home_projects_show_more')} >
</Button> {t('com_home_projects_show_more')}
</Button>
</div>
</div> </div>
</div> </div>
<div className="mt-10"> <div className="mt-10">