update
41
.gitignore
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.*
|
||||||
|
.yarn/*
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/versions
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# next.js
|
||||||
|
/.next/
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# debug
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
# env files (can opt-in for committing if needed)
|
||||||
|
.env*
|
||||||
|
|
||||||
|
# vercel
|
||||||
|
.vercel
|
||||||
|
|
||||||
|
# typescript
|
||||||
|
*.tsbuildinfo
|
||||||
|
next-env.d.ts
|
||||||
36
README.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
First, run the development server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
# or
|
||||||
|
yarn dev
|
||||||
|
# or
|
||||||
|
pnpm dev
|
||||||
|
# or
|
||||||
|
bun dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||||
|
|
||||||
|
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||||
|
|
||||||
|
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||||
|
|
||||||
|
## Learn More
|
||||||
|
|
||||||
|
To learn more about Next.js, take a look at the following resources:
|
||||||
|
|
||||||
|
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||||
|
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||||
|
|
||||||
|
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||||
|
|
||||||
|
## Deploy on Vercel
|
||||||
|
|
||||||
|
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||||
|
|
||||||
|
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||||
16
eslint.config.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { dirname } from "path";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
import { FlatCompat } from "@eslint/eslintrc";
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
|
const compat = new FlatCompat({
|
||||||
|
baseDirectory: __dirname,
|
||||||
|
});
|
||||||
|
|
||||||
|
const eslintConfig = [
|
||||||
|
...compat.extends("next/core-web-vitals", "next/typescript"),
|
||||||
|
];
|
||||||
|
|
||||||
|
export default eslintConfig;
|
||||||
7
next.config.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import type { NextConfig } from "next";
|
||||||
|
|
||||||
|
const nextConfig: NextConfig = {
|
||||||
|
/* config options here */
|
||||||
|
};
|
||||||
|
|
||||||
|
export default nextConfig;
|
||||||
8491
package-lock.json
generated
Normal file
31
package.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"name": "hurasoft",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start",
|
||||||
|
"lint": "next lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||||
|
"@types/next": "^9.0.0",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
|
"next": "^15.2.2",
|
||||||
|
"react": "^19.0.0",
|
||||||
|
"react-dom": "^19.0.0",
|
||||||
|
"swiper": "^11.2.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@eslint/eslintrc": "^3",
|
||||||
|
"@tailwindcss/postcss": "^4",
|
||||||
|
"@types/node": "^20",
|
||||||
|
"@types/react": "^19",
|
||||||
|
"@types/react-dom": "^19",
|
||||||
|
"eslint": "^9",
|
||||||
|
"eslint-config-next": "15.2.2",
|
||||||
|
"tailwindcss": "^4",
|
||||||
|
"typescript": "^5"
|
||||||
|
}
|
||||||
|
}
|
||||||
5
postcss.config.mjs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const config = {
|
||||||
|
plugins: ["@tailwindcss/postcss"],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
BIN
public/images/banner-article-sale.png
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
public/images/big-image-article.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
public/images/feedback-1.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
public/images/feedback-2.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
public/images/feedback-3.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
public/images/feedback-4.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
public/images/feedback-new.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
public/images/feedback-right.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
public/images/feedback.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
public/images/icon-adman.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
public/images/icon-anphat-new.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
public/images/icon-chatngay.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
public/images/icon-hacom-new.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
public/images/icon-hacom.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
public/images/icon-hura8.png
Normal file
|
After Width: | Height: | Size: 1014 B |
BIN
public/images/icon-nagakawa-new.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
public/images/icon-pico.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
public/images/icon-thanhliem-new.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
public/images/icon-thanhliem.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
public/images/icon-tuticare.png
Normal file
|
After Width: | Height: | Size: 818 B |
BIN
public/images/icon-xstore.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
public/images/icon_2024.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
public/images/icon_2024_new.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
public/images/image-form-mb.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
public/images/image-form.png
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
public/images/image-page-job-mb.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
public/images/image-page-job.png
Normal file
|
After Width: | Height: | Size: 115 KiB |
BIN
public/images/item-article-big.png
Normal file
|
After Width: | Height: | Size: 757 KiB |
BIN
public/images/item-article-small.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
public/images/logo-apollhome-new.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/images/logo-apollhome.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/images/logo-demxanh.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
public/images/logo-philong-new.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
public/images/logo-philong.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
public/images/logo-tainghe-new.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
public/images/logo-tainghe.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
public/images/logo-traphaco.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
public/images/logo-xstore.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
public/images/logo.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
28
src/app/layout.tsx
Normal 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
@@ -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">
|
||||||
|
Tư vấn và 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 lý cửa hàng nhỏ toàn diện, bao gồm: Quản lý
|
||||||
|
đơn hàng đa kênh, Kho hàng, Website và 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 và 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">Có gì 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
@@ -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, Hà 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
@@ -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 lý đơn hàng, hàng tồn kho và khách
|
||||||
|
hàng dành cho các doanh nghiệp vừa và 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 và 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
8
src/components/Slider.tsx
Normal 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
@@ -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
@@ -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
1
src/styles/style.css.map
Normal file
1111
src/styles/style.scss
Normal file
27
src/types/article.ts
Normal 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[];
|
||||||
|
}
|
||||||
27
tsconfig.json
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2017",
|
||||||
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"incremental": true,
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "next"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||