This commit is contained in:
2025-03-14 15:58:39 +07:00
commit abf8ab2c53
58 changed files with 11970 additions and 0 deletions

28
src/app/layout.tsx Normal file
View File

@@ -0,0 +1,28 @@
import "@fortawesome/fontawesome-free/css/all.min.css";
import "@/styles/style.css";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="vi">
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1"
/>
<meta httpEquiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Hurasoft</title>
<link rel="icon" href="/image" />
<body className="bg-white">
<Header />
<main>{children}</main>
<Footer />
</body>
</html>
);
}

599
src/app/page.tsx Normal file
View File

@@ -0,0 +1,599 @@
"use client";
import { useEffect } from "react";
import Image from "next/image";
import Link from "next/link";
import { format } from "date-fns";
import { homePageEffect } from "@/effects/homeEffect";
import { ArticlesData } from "../data/article";
import { ArticlesType } from "../types/article";
export default function Home() {
useEffect(() => {
const typingNode = document.getElementById("typewriter") as HTMLElement;
if (typingNode) {
homePageEffect.showTypingEffect(typingNode);
}
// slider đối tác
homePageEffect.startCarousel("#navheight", true, 3000);
console.log(ArticlesData);
}, []);
return (
<>
<div className="homepage">
<div className="box-slogan">
<div className="content-slogan">
<div className="main-sologan">
Cung cấp{" "}
<span id="typewriter">
các giải pháp tmđt toàn diện & chuyên nghiệp.
</span>
<span className="caret"></span>
</div>
<div className="note">
vấn phát triển website, marketing online, chăm sóc khách
hàng, tên miền, cloud hosting
</div>
<div className="group-btn flex items-center justify-center">
<Link href="/lien-he" className="btn btn-contact">
<i className="icon_2024 phone"></i>
<span>Liên hệ</span>
</Link>
</div>
</div>
</div>
<div className="box-customer">
<div className="container">
<h2 className="title">Khách hàng đng hành</h2>
<div className="navheight" id="navheight">
<div className="item-big">
<div className="item active">
<Image
src="/images/icon-hacom-new.png"
width={100}
height={100}
alt="hacom"
/>
</div>
<div className="item">
<Image
src="/images/logo-traphaco.png"
width={100}
height={100}
alt="traphaco"
/>
</div>
<div className="item">
<Image
src="/images/icon-anphat-new.png"
width={100}
height={100}
alt="anphat"
/>
</div>
<div className="item">
<Image
src="/images/icon-nagakawa-new.png"
width={100}
height={100}
alt="nagakawa"
/>
</div>
<div className="item">
<Image
src="/images/logo-tainghe.png"
width={100}
height={100}
alt="tainghe"
/>
</div>
<div className="item">
<Image
src="/images/logo-philong.png"
width={100}
height={100}
alt="philong"
/>
</div>
<div className="item">
<Image
src="/images/logo-apollhome-new.png"
width={100}
height={100}
alt="apollhome"
/>
</div>
</div>
<div className="item-big">
<div className="item active">
<Image
src="/images/logo-traphaco.png"
width={100}
height={100}
alt="traphaco"
/>
</div>
<div className="item">
<Image
src="/images/icon-anphat-new.png"
width={100}
height={100}
alt="anphat"
/>
</div>
<div className="item">
<Image
src="/images/icon-nagakawa-new.png"
width={100}
height={100}
alt="nagakawa"
/>
</div>
<div className="item">
<Image
src="/images/logo-tainghe.png"
width={100}
height={100}
alt="tainghe"
/>
</div>
<div className="item">
<Image
src="/images/logo-philong.png"
width={100}
height={100}
alt="philong"
/>
</div>
<div className="item">
<Image
src="/images/logo-apollhome-new.png"
width={100}
height={100}
alt="apollhome"
/>
</div>
<div className="item">
<Image
src="/images/icon-hacom-new.png"
width={100}
height={100}
alt="hacom"
/>
</div>
</div>
<div className="item-big">
<div className="item active">
<Image
src="/images/icon-anphat-new.png"
width={100}
height={100}
alt="anphat"
/>
</div>
<div className="item">
<Image
src="/images/icon-nagakawa-new.png"
width={100}
height={100}
alt="nagakawa"
/>
</div>
<div className="item">
<Image
src="/images/logo-tainghe.png"
width={100}
height={100}
alt="tainghe"
/>
</div>
<div className="item">
<Image
src="/images/logo-philong.png"
width={100}
height={100}
alt="philong"
/>
</div>
<div className="item">
<Image
src="/images/logo-apollhome-new.png"
width={100}
height={100}
alt="apollhome"
/>
</div>
<div className="item">
<Image
src="/images/icon-hacom-new.png"
width={100}
height={100}
alt="hacom"
/>
</div>
<div className="item">
<Image
src="/images/logo-traphaco.png"
width={100}
height={100}
alt="traphaco"
/>
</div>
</div>
<div className="item-big">
<div className="item active">
<Image
src="/images/icon-nagakawa-new.png"
width={100}
height={100}
alt="nagakawa"
/>
</div>
<div className="item">
<Image
src="/images/logo-tainghe.png"
width={100}
height={100}
alt="tainghe"
/>
</div>
<div className="item">
<Image
src="/images/logo-philong.png"
width={100}
height={100}
alt="philong"
/>
</div>
<div className="item">
<Image
src="/images/logo-apollhome-new.png"
width={100}
height={100}
alt="apollhome"
/>
</div>
<div className="item">
<Image
src="/images/icon-hacom-new.png"
width={100}
height={100}
alt="hacom"
/>
</div>
<div className="item">
<Image
src="/images/logo-traphaco.png"
width={100}
height={100}
alt="traphaco"
/>
</div>
<div className="item">
<Image
src="/images/icon-anphat-new.png"
width={100}
height={100}
alt="anphat"
/>
</div>
</div>
<div className="item-big">
<div className="item active">
<Image
src="/images/logo-tainghe.png"
width={100}
height={100}
alt="tainghe"
/>
</div>
<div className="item">
<Image
src="/images/logo-philong.png"
width={100}
height={100}
alt="philong"
/>
</div>
<div className="item">
<Image
src="/images/logo-apollhome-new.png"
width={100}
height={100}
alt="apollhome"
/>
</div>
<div className="item">
<Image
src="/images/icon-hacom-new.png"
width={100}
height={100}
alt="hacom"
/>
</div>
<div className="item">
<Image
src="/images/logo-traphaco.png"
width={100}
height={100}
alt="traphaco"
/>
</div>
<div className="item">
<Image
src="/images/icon-anphat-new.png"
width={100}
height={100}
alt="anphat"
/>
</div>
<div className="item">
<Image
src="/images/icon-nagakawa-new.png"
width={100}
height={100}
alt="nagakawa"
/>
</div>
</div>
<div className="item-big">
<div className="item active">
<Image
src="/images/logo-philong.png"
width={100}
height={100}
alt="philong"
/>
</div>
<div className="item">
<Image
src="/images/logo-apollhome-new.png"
width={100}
height={100}
alt="apollhome"
/>
</div>
<div className="item">
<Image
src="/images/icon-hacom-new.png"
width={100}
height={100}
alt="hacom"
/>
</div>
<div className="item">
<Image
src="/images/logo-traphaco.png"
width={100}
height={100}
alt="traphaco"
/>
</div>
<div className="item">
<Image
src="/images/icon-anphat-new.png"
width={100}
height={100}
alt="anphat"
/>
</div>
<div className="item">
<Image
src="/images/icon-nagakawa-new.png"
width={100}
height={100}
alt="nagakawa"
/>
</div>
<div className="item">
<Image
src="/images/logo-tainghe.png"
width={100}
height={100}
alt="tainghe"
/>
</div>
</div>
<div className="item-big">
<div className="item active">
<Image
src="/images/logo-apollhome-new.png"
width={100}
height={100}
alt="apollhome"
/>
</div>
<div className="item">
<Image
src="/images/icon-hacom-new.png"
width={100}
height={100}
alt="hacom"
/>
</div>
<div className="item">
<Image
src="/images/logo-traphaco.png"
width={100}
height={100}
alt="traphaco"
/>
</div>
<div className="item">
<Image
src="/images/icon-anphat-new.png"
width={100}
height={100}
alt="anphat"
/>
</div>
<div className="item">
<Image
src="/images/icon-nagakawa-new.png"
width={100}
height={100}
alt="nagakawa"
/>
</div>
<div className="item">
<Image
src="/images/logo-tainghe.png"
width={100}
height={100}
alt="tainghe"
/>
</div>
<div className="item">
<Image
src="/images/logo-philong.png"
width={100}
height={100}
alt="philong"
/>
</div>
</div>
</div>
</div>
</div>
<div className="box-product">
<div className="container">
<h2 className="title">Sản phẩm</h2>
<div className="list-product flex">
<div className="item-product">
<div className="top">
<div className="icon">
<Image
src="/images/icon-hura8.png"
width={100}
height={100}
alt="hura 8"
/>
</div>
<p className="txt line-clamp-5">
Phần mềm tạo website TMĐT chạy nên nền tảng Cloud dành cho
doanh nghiệp lớn
</p>
</div>
<a href="//hura8.com" target="_blank" className="more">
Xem thêm <i className="fa-solid fa-arrow-right"></i>
</a>
</div>
<div className="item-product">
<div className="top">
<div className="icon">
<Image
src="/images/logo-xstore.png"
width={93}
height={35}
alt="xstore"
/>
</div>
<p className="txt line-clamp-5">
Nền tảng quản cửa hàng nhỏ toàn diện, bao gồm: Quản
đơn hàng đa kênh, Kho hàng, Website POS
</p>
</div>
<a href="//xstore.vn" target="_blank" className="more">
Xem thêm <i className="fa-solid fa-arrow-right"></i>
</a>
</div>
<div className="item-product">
<div className="top">
<div className="icon">
<Image
src="/images/icon-adman.png"
width={100}
height={100}
alt="icon-adman"
/>
</div>
<p className="txt line-clamp-5">
Nền tảng marketing toàn diện dành cho các chuyên gia.
</p>
</div>
<a href="//adman.vn" target="_blank" className="more">
Xem thêm <i className="fa-solid fa-arrow-right"></i>
</a>
</div>
<div className="item-product chatngay">
<div className="top">
<div className="icon">
<Image
src="/images/icon-chatngay.png"
width={100}
height={100}
alt="icon-chatngay"
/>
</div>
<p className="txt line-clamp-5">
Phần mềm hỗ trợ, cskh tích hợp website giúp khách hàng tương
tác nhanh chóng thuận tiện.
</p>
</div>
<a href="//chatngay.com" target="_blank" className="more">
Xem thêm <i className="fa-solid fa-arrow-right"></i>
</a>
</div>
</div>
</div>
</div>
<div className="box-article">
<div className="container">
<h2 className="title"> mới?</h2>
<div className="content-item-article" id="js-article-new">
{ArticlesData.list.slice(0, 1).map((articles) => (
<div className="flex" key={articles.id}>
<div className="info">
<div className="tag-blog flex items-center">
<i className="icon_2024 blog"></i>
<span>Blog</span>
</div>
<a href={articles.url} className="name line-clamp-4">
{articles.title}
</a>
<div className="summary line-clamp-4">
{articles.summary}
</div>
<a href={articles.url} className="more">
Chi tiết <i className="fa-solid fa-arrow-right"></i>
</a>
<div className="info-author">
<div className="author flex items-center">
<span>Đăng bởi</span>
<span className="name-author">Admin</span>
</div>
<div className="time">
<i className="far fa-clock"></i>{" "}
<span>
{format(
new Date(articles.last_update * 1000),
"dd/MM/yyyy HH:mm"
)}
</span>
</div>
</div>
</div>
<div className="image-right">
<img
src={`https://hurasoft8.hurasoft.com/${articles.image.large}`}
width={100}
height={100}
alt={articles.title}
/>
</div>
</div>
))}
</div>
</div>
</div>
</div>
</>
);
}

63
src/components/Footer.tsx Normal file
View File

@@ -0,0 +1,63 @@
export default function Footer() {
return (
<div className="footer">
<div className="container">
<div className="main-footer flex">
<div className="item-footer big">
<h3 className="title">Công ty TNHH Hurasoft</h3>
<div className="content">
<a
href="https://maps.app.goo.gl/fimdgxskWrcDrKbQ7"
target="_blank"
className="link"
>
Đa chỉ: Tầng 5 - Số 3, ngõ 18 Yên Lãng, Đng Đa, Nội
</a>
<a href="tel:02422138068" className="link">
Hotline: 02422.138.068{" "}
</a>
<a href="mailto:hotro@hurasoft.com" className="link">
Email: hotro@hurasoft.com
</a>
</div>
</div>
<div className="item-footer">
<h3 className="title">Thông tin</h3>
<div className="content">
<a href="/job" className="link">
Tuyển dụng
</a>
<a href="/blog" className="link">
Blog
</a>
<a href="/lien-he" className="link">
Liên hệ
</a>
</div>
</div>
<div className="item-footer">
<h3 className="title">Sản phẩm</h3>
<div className="content">
<a href="//hura8.com" target="_blank" className="link">
Hura8
</a>
<a href="//xstore.vn" target="_blank" className="link">
XStore
</a>
<a href="//adman.vn" target="_blank" className="link">
AdMan
</a>
<a href="//chatngay.com" target="_blank" className="link">
Chatngay
</a>
</div>
</div>
</div>
<div className="bottom-footer">Copyright @2025 Hurasoft</div>
</div>
</div>
);
}

112
src/components/Header.tsx Normal file
View File

@@ -0,0 +1,112 @@
import Link from "next/link";
import Image from "next/image";
export default function Header() {
return (
<header className="header">
<div className="container">
<div className="content-header-main flex items-center justify-between">
<Link href="/" className="logo">
<Image src="/images/logo.png" width={100} height={100} alt="logo" />
</Link>
<div className="menu-right flex items-center">
<div className="item">
<Link href="/page/dich-vu.html" className="title">
Sản phẩm
</Link>
<div className="hover-menu">
<div className="item-menu">
<div className="top">
<div className="icon">
<Image
src="/images/icon-hura8.png"
width={100}
height={16}
alt="hura 8"
/>
</div>
<p className="txt line-clamp-4">
Tốt nhất cho hoạt đng thương mại điện tử của doanh nghiệp
</p>
</div>
<a href="" className="more">
<i className="fa-solid fa-arrow-right"></i>
</a>
</div>
<div className="item-menu">
<div className="top">
<div className="icon">
<Image
src="/images/icon-xstore.png"
width={100}
height={16}
alt="xstore"
/>
</div>
<p className="txt line-clamp-4">
Bộ sản phẩm về quản đơn hàng, hàng tồn kho khách
hàng dành cho các doanh nghiệp vừa nhỏ. Đưc bổ sung
với một POS thông minh.
</p>
</div>
<a href="" className="more">
<i className="fa-solid fa-arrow-right"></i>
</a>
</div>
<div className="item-menu">
<div className="top">
<div className="icon">
<Image
src="/images/icon-adman.png"
width={100}
height={16}
alt="icon-adman"
/>
</div>
<p className="txt line-clamp-4">
Nền tảng tiếp thị toàn diện dành cho các chuyên gia.
</p>
</div>
<a href="" className="more">
<i className="fa-solid fa-arrow-right"></i>
</a>
</div>
<div className="item-menu chatngay">
<div className="top">
<div className="icon">
<Image
src="/images/icon-chatngay.png"
width={100}
height={16}
alt="icon-chatngay"
/>
</div>
<p className="txt line-clamp-4">
Giúp khách hàng đang truy cập website trò chuyện với bạn
một cách đơn giản, nhanh chóng thuận tiện.
</p>
</div>
<a href="" className="more">
<i className="fa-solid fa-arrow-right"></i>
</a>
</div>
</div>
</div>
<Link href="/tuyen-dung" className="item">
Tuyển dụng
</Link>
<Link href="/tin-tuc" className="item">
Blog
</Link>
<Link href="/lien-he" className="item">
Liên hệ
</Link>
<Link href="javascript:void(0)" className="item">
<i className="icon_2024 global"></i>
</Link>
</div>
</div>
</div>
</header>
);
}

View File

@@ -0,0 +1,8 @@
import { Swiper, SwiperSlide } from "swiper/react";
import "swiper/swiper-bundle.min.css";
const Slider = () => {
return <></>;
};
export default Slider;

207
src/data/article.ts Normal file
View File

@@ -0,0 +1,207 @@
import { ArticlesType } from '../types/article';
export const ArticlesData: ArticlesType = {
"total": 11,
"list": [
{
"id": 729,
"title": "test bài viết tin tức",
"summary": "An toàn thông tin website đề cập đến các biện pháp và quy trình nhằm bảo vệ dữ liệu và thông tin trên website khỏi các mối đe dọa như hacker, phần mềm độc hại, và các cuộc tấn công mạng khác. Điều này bao gồm việc bảo vệ dữ liệu người dùng, đảm bảo các giao dịch trực tuyến được mã hóa an toàn, và duy trì tính toàn vẹn của các tài nguyên trên website.",
"request_path": "/test-bai-viet-tin-tuc",
"review_rate": 0,
"review_count": 0,
"visit": 0,
"like_count": 0,
"article_time": 1734325200,
"allow_se_index": 1,
"comment_count": 0,
"comment_rate": 0,
"last_update": 1734408362,
"image": {
"thumb": "/media/article/t-item-article-big.png",
"large": "/media/article/l-item-article-big.png"
},
"url": "/test-bai-viet-tin-tuc"
},
{
"id": 728,
"title": "Hướng dẫn theo dõi và cải thiện lượng truy cập website bằng google analytics",
"summary": "",
"request_path": "/huong-dan-theo-doi-va-cai-thien-luong-truy-cap-website-bang-google-analytics",
"review_rate": 0,
"review_count": 0,
"visit": 0,
"like_count": 0,
"article_time": 1731646800,
"allow_se_index": 1,
"comment_count": 0,
"comment_rate": 0,
"last_update": 1734408339,
"image": {
"thumb": "/media/article/t-advisor-financial-business-analytics-woman-team-an.png",
"large": "/media/article/l-advisor-financial-business-analytics-woman-team-an.png"
},
"url": "/huong-dan-theo-doi-va-cai-thien-luong-truy-cap-website-bang-google-analytics"
},
{
"id": 727,
"title": "Yếu tố ảnh hưởng tới quyết định mua hàng online của người dùng trên website",
"summary": "",
"request_path": "/yeu-to-anh-huong-toi-quyet-dinh-mua-hang-online-cua-nguoi-dung-tren-website",
"review_rate": 0,
"review_count": 0,
"visit": 0,
"like_count": 0,
"article_time": 1731646800,
"allow_se_index": 1,
"comment_count": 0,
"comment_rate": 0,
"last_update": 1732517016,
"image": {
"thumb": "/media/article/t-fashion-blogger-concept-young-asian-women-selling-.jpg",
"large": "/media/article/l-fashion-blogger-concept-young-asian-women-selling-.jpg"
},
"url": "/yeu-to-anh-huong-toi-quyet-dinh-mua-hang-online-cua-nguoi-dung-tren-website"
},
{
"id": 726,
"title": "An toàn thông tin website",
"summary": "An toàn thông tin website đề cập đến các biện pháp và quy trình nhằm bảo vệ dữ liệu và thông tin trên website khỏi các mối đe dọa như hacker, phần mềm độc hại, và các cuộc tấn công mạng khác.",
"request_path": "/an-toan-thong-tin-website",
"review_rate": 0,
"review_count": 0,
"visit": 0,
"like_count": 0,
"article_time": 1731646800,
"allow_se_index": 1,
"comment_count": 0,
"comment_rate": 0,
"last_update": 1734319905,
"image": {
"thumb": "/media/article/t-cyber-security-concept-digital-art_23-2151637760.jpg",
"large": "/media/article/l-cyber-security-concept-digital-art_23-2151637760.jpg"
},
"url": "/an-toan-thong-tin-website"
},
{
"id": 725,
"title": "Làm thế nào để tăng lượng truy cập cho website của bạn?",
"summary": "",
"request_path": "/lam-the-nao-de-tang-luong-truy-cap-cho-website-cua-ban",
"review_rate": 0,
"review_count": 0,
"visit": 0,
"like_count": 0,
"article_time": 1731646800,
"allow_se_index": 1,
"comment_count": 0,
"comment_rate": 0,
"last_update": 1732517149,
"image": {
"thumb": "/media/article/t-technology-hologram-indoors_23-2151833340.jpg",
"large": "/media/article/l-technology-hologram-indoors_23-2151833340.jpg"
},
"url": "/lam-the-nao-de-tang-luong-truy-cap-cho-website-cua-ban"
},
{
"id": 724,
"title": "Xu hướng cá nhân hóa trải nghiệm người dùng trong thương mại điện tử",
"summary": "",
"request_path": "/xu-huong-ca-nhan-hoa-trai-nghiem-nguoi-dung-trong-thuong-mai-dien-tu",
"review_rate": 0,
"review_count": 0,
"visit": 0,
"like_count": 0,
"article_time": 1731646800,
"allow_se_index": 1,
"comment_count": 0,
"comment_rate": 0,
"last_update": 1732517289,
"image": {
"thumb": "/media/article/t-3d-representation-reselling-market_23-2150473097.jpg",
"large": "/media/article/l-3d-representation-reselling-market_23-2150473097.jpg"
},
"url": "/xu-huong-ca-nhan-hoa-trai-nghiem-nguoi-dung-trong-thuong-mai-dien-tu"
},
{
"id": 723,
"title": "Thu hút người dùng bằng minigame trên website",
"summary": "",
"request_path": "/marketing-bang-minigame-tren-website",
"review_rate": 0,
"review_count": 0,
"visit": 0,
"like_count": 0,
"article_time": 1731646800,
"allow_se_index": 1,
"comment_count": 0,
"comment_rate": 0,
"last_update": 1732517364,
"image": {
"thumb": "/media/article/t-lucky-dice-game-background_23-2150971831.jpg",
"large": "/media/article/l-lucky-dice-game-background_23-2150971831.jpg"
},
"url": "/marketing-bang-minigame-tren-website"
},
{
"id": 722,
"title": "Chiến lược marketing website thương mại điện tử nổi bật 2024",
"summary": "",
"request_path": "/nhung-chien-luoc-marketing-website-thuong-mai-dien-tu-noi-bat-2024",
"review_rate": 0,
"review_count": 0,
"visit": 0,
"like_count": 0,
"article_time": 1731646800,
"allow_se_index": 1,
"comment_count": 0,
"comment_rate": 0,
"last_update": 1732083342,
"image": {
"thumb": "/media/article/t-rectangle-3.png",
"large": "/media/article/l-rectangle-3.png"
},
"url": "/nhung-chien-luoc-marketing-website-thuong-mai-dien-tu-noi-bat-2024"
},
{
"id": 721,
"title": "Lợi thế nào cho đơn vị bán hàng qua website cạnh tranh với các sàn thương mại điện tử 2024 ?",
"summary": "",
"request_path": "/loi-the-ban-hang-qua-website-so-voi-cac-san-thuong-mai-dien-tu-2024",
"review_rate": 0,
"review_count": 0,
"visit": 0,
"like_count": 0,
"article_time": 1731646800,
"allow_se_index": 1,
"comment_count": 0,
"comment_rate": 0,
"last_update": 1732517547,
"image": {
"thumb": "/media/article/t-cardboard-boxes-conveyor-belt-warehouse_632498-117.jpg",
"large": "/media/article/l-cardboard-boxes-conveyor-belt-warehouse_632498-117.jpg"
},
"url": "/loi-the-ban-hang-qua-website-so-voi-cac-san-thuong-mai-dien-tu-2024"
},
{
"id": 720,
"title": "Vai trò quan trọng của việc nâng cấp phần mềm",
"summary": "",
"request_path": "/vai-tro-quan-trong-cua-viec-nang-cap-phan-mem",
"review_rate": 0,
"review_count": 0,
"visit": 0,
"like_count": 0,
"article_time": 1731646800,
"allow_se_index": 1,
"comment_count": 0,
"comment_rate": 0,
"last_update": 1732517477,
"image": {
"thumb": "/media/article/t-programming-background-with-person-working-with-co.jpg",
"large": "/media/article/l-programming-background-with-person-working-with-co.jpg"
},
"url": "/vai-tro-quan-trong-cua-viec-nang-cap-phan-mem"
}
]
}

78
src/effects/homeEffect.ts Normal file
View File

@@ -0,0 +1,78 @@
"use client";
import { useEffect } from "react";
function showTypingEffect(typingNode: HTMLElement): void {
if (!typingNode) return;
const text = typingNode.innerText;
typingNode.innerText = "";
let i = 0;
const typing = setInterval(() => {
if (i < text.length) {
typingNode.innerText += text.charAt(i);
i++;
} else {
clearInterval(typing);
}
}, 100);
}
function startCarousel(containerSelector: string, loop: boolean, startDelay: number): () => void {
const containers: NodeListOf<HTMLElement> = document.querySelectorAll(`${containerSelector} .item-big`);
const DELAY: number = 120; // Thời gian delay giữa các item trong container
const INTERVAL: number = startDelay; // Thời gian trì hoãn trước khi bắt đầu carousel
// Cập nhật trạng thái item (active, previous)
const updateItemState = (items: NodeListOf<HTMLElement>, activeIndex: number): number => {
const nextIndex: number = (activeIndex + 1) % items.length;
resetItemsState(items); // Xóa các trạng thái 'active' và 'previous'
markItemState(items, activeIndex, nextIndex); // Đánh dấu item hiện tại và item tiếp theo
return nextIndex;
};
// Hàm reset các trạng thái 'active' và 'previous' của các items
const resetItemsState = (items: NodeListOf<HTMLElement>): void => {
items.forEach((item: HTMLElement) => {
item.classList.remove('active', 'previous');
});
};
// Hàm đánh dấu item hiện tại và item tiếp theo
const markItemState = (items: NodeListOf<HTMLElement>, activeIndex: number, nextIndex: number): void => {
items[activeIndex].classList.add('previous');
items[nextIndex].classList.add('active');
};
// Hàm xử lý vòng lặp carousel cho mỗi container
const processContainer = (container: HTMLElement, index: number): void => {
const items: NodeListOf<HTMLElement> = container.querySelectorAll('.item');
let activeIndex: number = Array.from(items).findIndex((item: HTMLElement) => item.classList.contains('active')) || 0;
setTimeout(() => {
activeIndex = updateItemState(items, activeIndex);
// Nếu không muốn loop và đã đến item cuối, dừng vòng lặp
if (!loop && activeIndex === items.length - 1) {
clearInterval(intervalId);
}
}, index * DELAY); // Delay riêng cho mỗi container
};
// Hàm xử lý tất cả các container
const processContainers = (): void => {
containers.forEach((container: HTMLElement, index: number) => {
processContainer(container, index);
});
};
// Chạy vòng lặp carousel theo khoảng thời gian INTERVAL
const intervalId: NodeJS.Timeout = setInterval(processContainers, INTERVAL);
// Trả về hàm dừng vòng lặp khi cần
return () => clearInterval(intervalId);
}
export const homePageEffect = {
showTypingEffect,
startCarousel
};

1082
src/styles/style.css Normal file

File diff suppressed because it is too large Load Diff

1
src/styles/style.css.map Normal file

File diff suppressed because one or more lines are too long

1111
src/styles/style.scss Normal file

File diff suppressed because it is too large Load Diff

27
src/types/article.ts Normal file
View File

@@ -0,0 +1,27 @@
export interface ArticleImage {
thumb: string; // Đường dẫn ảnh thu nhỏ
large: string; // Đường dẫn ảnh lớn
}
export interface Article {
id: number;
title: string;
summary: string;
request_path: string;
review_rate: number;
review_count: number;
visit: number;
like_count: number;
article_time: number;
allow_se_index: number;
comment_count: number;
comment_rate: number;
last_update: number;
image: ArticleImage; // Đối tượng ảnh
url: string;
}
export interface ArticlesType {
total: number;
list: Article[];
}