This commit is contained in:
2026-03-13 13:54:45 +07:00
parent a8e30f32a0
commit 25111ff10e
120 changed files with 4213 additions and 4859 deletions

View File

@@ -0,0 +1,67 @@
'use client';
import ItemArticle from '@/components/Common/ItemArticle';
import Link from 'next/link';
import Image from 'next/image';
import { getArticles } from '@/lib/api/article';
import { useApiData } from '@/hooks/useApiData';
import type { ListArticle } from '@/types/article/TypeListArticle';
export const BoxArticleMid = () => {
const { data: articles } = useApiData(
() => getArticles(),
[],
{ initialData: [] as ListArticle },
);
return (
<div className="box-article-home-middle grid grid-cols-3 gap-2">
<div className="box-article-tech col-left-article boder-radius-10 border-box-article col-span-2">
<p className="title-box-article font-[600]">Tin công nghệ</p>
<div className="list-article-tech">
{articles.slice(0, 9).map((item) => (
<ItemArticle item={item} key={item.id} />
))}
</div>
<Link
href="/tin-cong-nghe"
className="btn-article-col flex items-center justify-center gap-2 font-[500]"
>
Xem tất cả
</Link>
</div>
<div className="col-right-article flex-1">
<div className="box-article-hot border-box-article boder-radius-10">
<p className="title-box-article font-bold">Tin nổi bật</p>
<div className="list-article-hot">
{articles.slice(0, 5).map((item) => (
<div className="item-article flex gap-4" key={item.id}>
<Link href={item.url} className="img-article boder-radius-10 relative">
<Image
className="boder-radius-10"
src={item.image.original}
fill
alt={item.title}
/>
<i className="sprite sprite-icon-play-video-detail icon-video-feature incon-play-youtube"></i>
<i className="sprite sprite-play-youtube incon-play-youtube"></i>
</Link>
<div className="content-article content-article-item flex flex-1 flex-col">
<Link href={item.url} className="title-article">
<h3 className="line-clamp-2 font-[400]">{item.title}</h3>
</Link>
<p className="time-article flex items-center gap-2">
<i className="sprite sprite-clock-item-article"></i>
<span>{item.createDate}</span>
</p>
<p className="descreption-article line-clamp-2">{item.summary}</p>
</div>
</div>
))}
</div>
</div>
</div>
</div>
);
};

View File

@@ -0,0 +1,55 @@
'use client';
import { Swiper, SwiperSlide } from 'swiper/react';
import { Autoplay, Navigation, Pagination, Thumbs } from 'swiper/modules';
import Image from 'next/image';
import Link from 'next/link';
import { getArticles } from '@/lib/api/article';
import { useApiData } from '@/hooks/useApiData';
import type { ListArticle } from '@/types/article/TypeListArticle';
export const BoxArticleReview = () => {
const { data: articles } = useApiData(
() => getArticles(),
[],
{ initialData: [] as ListArticle },
);
return (
<div className="box-article-category page-hompage">
<div className="box-article-global box-artice-review">
<div className="title-box-product-home mb-5 flex flex-col items-center">
<p className="title font-[500]">Review sản phẩm</p>
<p className="border-title"></p>
</div>
<div className="list-article-global">
<Swiper
modules={[Autoplay, Navigation, Pagination, Thumbs]}
spaceBetween={15}
slidesPerView={3}
loop={true}
>
{articles.map((item) => (
<SwiperSlide key={item.id}>
<div className="item-article">
<Link href={item.url} className="img-article">
<Image src={item.image.original} fill alt={item.title} />
</Link>
<div className="content-article-item">
<Link href={item.url} className="title font-weight-500 line-clamp-2">
{item.title}
</Link>
<div className="time-aricle-item flex items-center">
<i className="sprite sprite-clock-item-article"></i>
<span>{item.createDate}</span>
</div>
</div>
</div>
</SwiperSlide>
))}
</Swiper>
</div>
</div>
</div>
);
};

View File

@@ -0,0 +1,130 @@
'use client';
import Link from 'next/link';
import { FaYoutube } from 'react-icons/fa6';
import Image from 'next/image';
import useFancybox from '@/hooks/useFancybox';
import { getArticleVideos } from '@/lib/api/article';
import { useApiData } from '@/hooks/useApiData';
import type { ListArticle } from '@/types/article/TypeListArticle';
export const BoxVideoArticle = () => {
const { data: videos } = useApiData(
() => getArticleVideos(),
[],
{ initialData: [] as ListArticle },
);
const getYoutubeEmbedUrl = (url: string): string => {
try {
const urlObj = new URL(url);
if (urlObj.hostname.includes('youtube.com')) {
const videoId = urlObj.searchParams.get('v');
if (videoId) {
return `https://www.youtube.com/embed/${videoId}?autoplay=1`;
}
}
if (urlObj.hostname.includes('youtu.be')) {
const videoId = urlObj.pathname.replace('/', '');
if (videoId) {
return `https://www.youtube.com/embed/${videoId}?autoplay=1`;
}
}
return url;
} catch {
return url;
}
};
const [fancyboxRef] = useFancybox({
closeButton: 'auto',
dragToClose: true,
});
return (
<div className="box-video-article boder-radius-10">
<div className="title-video-article flex justify-between">
<p className="title font-bold">Youtube channel</p>
<Link
href="https://www.youtube.com/c/NGUYENCONGPC"
className="follow-youtube flex items-center gap-2"
>
<FaYoutube />
<span className="font-bold">Theo dõi trên YouTube</span>
</Link>
</div>
<div className="list-video-article flex justify-between gap-2">
<div className="box-left" ref={fancyboxRef}>
{videos.slice(0, 1).map((item) => (
<div className="item-article-video d-flex w-50 gap-10" key={item.id}>
<Link
href={getYoutubeEmbedUrl(item.external_url)}
className="img-article img-article-video boder-radius-10 relative"
data-fancybox
>
<Image
src={item.image.original}
width={430}
height={310}
className="boder-radius-10"
alt={item.title}
/>
<i className="sprite sprite-big-play-video-article icon-play"></i>
<Image
className="icon-play-small"
src="https://nguyencongpc.vn/static/assets/nguyencong_2023/images/small-play-youtube.png"
alt="play"
width={58}
height={41}
/>
</Link>
<Link
href={getYoutubeEmbedUrl(item.external_url)}
className="title-article-video flex-1"
data-fancybox
>
{item.title}
</Link>
</div>
))}
</div>
<div className="box-right grid grid-cols-2 gap-2">
{videos.slice(1, 7).map((item) => (
<div className="item-article-video flex w-50 gap-2" key={item.id}>
<Link
href={getYoutubeEmbedUrl(item.external_url)}
className="img-article img-article-video boder-radius-10 relative"
data-fancybox
>
<Image
src={item.image.original}
width={430}
height={310}
className="boder-radius-10"
alt={item.title}
/>
<i className="sprite sprite-big-play-video-article icon-play"></i>
<Image
className="icon-play-small"
src="https://nguyencongpc.vn/static/assets/nguyencong_2023/images/small-play-youtube.png"
alt="play"
width={58}
height={41}
/>
</Link>
<Link
href={getYoutubeEmbedUrl(item.external_url)}
className="title-article-video flex-1"
data-fancybox
>
{item.title}
</Link>
</div>
))}
</div>
</div>
</div>
);
};

View File

@@ -0,0 +1,52 @@
'use client';
import React from 'react';
import Link from 'next/link';
import { Breadcrumb } from '@components/Common/Breadcrumb';
import { ArticleTopLeft } from '../ArticleTopLeft';
import { ArticleTopRight } from '../ArticleTopRight';
import { BoxVideoArticle } from './BoxVideoArticle';
import { BoxArticleMid } from './BoxArticleMid';
import { BoxArticleReview } from './BoxArticleReview';
import { getArticleCategories } from '@/lib/api/article';
import { useApiData } from '@/hooks/useApiData';
import type { TypeArticleCategory } from '@/types/article/ListCategoryArticle';
const ArticleHome = () => {
const breadcrumbItems = [{ name: 'Tin tức', url: '/tin-tuc' }];
const { data: categories } = useApiData(
() => getArticleCategories(),
[],
{ initialData: [] as TypeArticleCategory[] },
);
return (
<section className="page-article pb-10">
<div className="container">
<Breadcrumb items={breadcrumbItems} />
<div className="tabs-category-article flex items-center">
{categories.map((item, index) => (
<Link href={item.url} key={`${item.id}-${index}`} className="item-tab-article">
<h2 className="title-cate-article font-[400]">{item.title}</h2>
</Link>
))}
</div>
<div className="box-article-home-top grid grid-cols-3 gap-3">
<div className="col-left-article border-box-article box-new-article boder-radius-10 col-span-2">
<ArticleTopLeft />
</div>
<ArticleTopRight />
</div>
<BoxVideoArticle />
<BoxArticleMid />
<BoxArticleReview />
</div>
</section>
);
};
export default ArticleHome;