sent-test-work
443
README.md
|
|
@ -1,328 +1,115 @@
|
|||
|
||||
### Next.js Enterprise Boilerplate
|
||||
|
||||
</br>
|
||||
|
||||
[![GitHub Actions Workflow Status][check-workflow-badge]][check-workflow-badge-link] [![GitHub License][github-license-badge]][github-license-badge-link] [![GitHub contributors][github-contributors-badge]][github-contributors-badge-link] [![Discord][discord-badge]][discord-badge-link] [![Blazity][made-by-blazity-badge]][made-by-blazity-badge-link]
|
||||
|
||||
Welcome to the _Next.js Enterprise Boilerplate_, an open-source template for enterprise projects! It's loaded with features that'll help you build a high-performance, maintainable, and enjoyable app. We've done all the heavy lifting for you, so sit back, relax, and get ready to conquer the world with your incredible app! 🌍
|
||||
|
||||
> [!NOTE]
|
||||
> **Blazity** is a group of Next.js/Headless experts. Contact us at [contact@blazity.com](https://blazity.com) if you’d like to talk about your project or just to have a chat with us
|
||||
|
||||
### Integrated features
|
||||
|
||||
With this template you will get all the awesomeness you need:
|
||||
|
||||
- 🏎️ **[Next.js 15](https://nextjs.org/)** - Fast by default, with config optimized for performance (with **App Directory**)
|
||||
- 💅 **[Tailwind CSS](https://tailwindcss.com/)** - A utility-first CSS framework for rapid UI development
|
||||
- ✨ **[ESlint](https://eslint.org/)** and **[Prettier](https://prettier.io/)** - For clean, consistent, and error-free code
|
||||
- 🛠️ **[Extremely strict TypeScript](https://www.typescriptlang.org/)** - With [`ts-reset`](https://github.com/total-typescript/ts-reset) library for ultimate type safety
|
||||
- 🚀 **[GitHub Actions](https://github.com/features/actions)** - Pre-configured actions for smooth workflows, including Bundle Size and performance stats
|
||||
- 💯 **Perfect Lighthouse score** - Because performance matters
|
||||
- **[Bundle analyzer plugin](https://www.npmjs.com/package/@next/bundle-analyzer)** - Keep an eye on your bundle size
|
||||
- **[Jest](https://jestjs.io/)** and **[React Testing Library](https://testing-library.com/react)** - For rock-solid unit and integration tests
|
||||
- **[Playwright](https://playwright.dev/)** - Write end-to-end tests like a pro
|
||||
- **[Storybook](https://storybook.js.org/)** - Create, test, and showcase your components
|
||||
- **Smoke Testing** and **Acceptance Tests** - For confidence in your deployments
|
||||
- **[Conventional commits git hook](https://www.conventionalcommits.org/)** - Keep your commit history neat and tidy
|
||||
- **[Observability](https://opentelemetry.io/)** - Open Telemetry integration for seamless monitoring
|
||||
- **[Absolute imports](https://nextjs.org/docs/advanced-features/module-path-aliases)** - No more spaghetti imports
|
||||
- **[Health checks](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/)** - Kubernetes-compatible for robust deployments
|
||||
- **[Radix UI](https://www.radix-ui.com/)** - Headless UI components for endless customization
|
||||
- **[CVA](http://cva.style/)** - Create a consistent, reusable, and atomic design system
|
||||
- **[Renovate BOT](https://www.whitesourcesoftware.com/free-developer-tools/renovate)** - Auto-updating dependencies, so you can focus on coding
|
||||
- **[Patch-package](https://www.npmjs.com/package/patch-package)** - Fix external dependencies without losing your mind
|
||||
- **Components coupling and cohesion graph** - A tool for managing component relationships
|
||||
- **[Semantic Release](https://github.com/semantic-release/semantic-release)** - for automatic changelog
|
||||
- **[T3 Env](https://env.t3.gg/)** - Manage your environment variables with ease
|
||||
|
||||
### More features
|
||||
|
||||
**nefi** (next-enterprise feature integrations) is an AI agent that will help configuring the boilerplate to your needs using natural language. It can remove/install dependencies, modify files, manage git and integrate various solutions into your project.
|
||||
|
||||
Simply set up the boilerplate, follow guide [in the getting started section](#getting-started) and type `npx nefi` in your terminal!
|
||||
|
||||
Here's an example video of [nefi](https://nefi.ai/) integrating [Clerk](https://clerk.com/) auth solutions with one command, no API keys and no manual configuration needed!
|
||||
|
||||
|
||||
https://github.com/user-attachments/assets/5c13a110-7389-4859-909f-60a7f623e47d
|
||||
|
||||
|
||||
Leave a ⭐ for [nefi on GitHub](https://github.com/blazity/nefi) and check out the [nefi.ai docs](https://nefi.ai/)!
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Next.js Enterprise Boilerplate](#nextjs-enterprise-boilerplate)
|
||||
- [Features](#features)
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Getting Started](#-getting-started)
|
||||
- [Deployment](#-deployment)
|
||||
- [Scripts Overview](#-scripts-overview)
|
||||
- [Coupling Graph](#-coupling-graph)
|
||||
- [Testing](#-testing)
|
||||
- [Running Tests](#running-tests)
|
||||
- [Acceptance Tests](#acceptance-tests)
|
||||
- [Smoke Testing](#smoke-testing)
|
||||
- [Styling and Design System](#-styling-and-design-system)
|
||||
- [CVA - A New Approach to Variants](#cva---a-new-approach-to-variants)
|
||||
- [State Management](#-state-management)
|
||||
- [Zustand](#zustand)
|
||||
- [Jotai](#jotai)
|
||||
- [Recoil](#recoil)
|
||||
- [Environment Variables handling](#-environment-variables-handling)
|
||||
- [Contribution](#-contribution)
|
||||
- [Support](#support)
|
||||
- [License](#-license)
|
||||
- [Contributors](#contributors)
|
||||
|
||||
## 🎯 Getting Started
|
||||
|
||||
To get started with this boilerplate, follow these steps:
|
||||
|
||||
1. Fork & clone repository:
|
||||
|
||||
```bash
|
||||
## Don't forget to ⭐ star and fork it first :)
|
||||
git clone https://github.com/<your_username>/next-enterprise.git
|
||||
```
|
||||
|
||||
2. Install the dependencies:
|
||||
|
||||
```bash
|
||||
pnpm install --frozen-lockfile
|
||||
```
|
||||
|
||||
3. Run the development server:
|
||||
|
||||
```bash
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
4. Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
5. This project uses a git hook to enforce [conventional commits](https://github.com/qoomon/git-conventional-commits). To install the git hook, run the following command in the root directory of the project:
|
||||
|
||||
```sh
|
||||
brew install pre-commit
|
||||
pre-commit install -t commit-msg
|
||||
```
|
||||
|
||||
## 🚀 Deployment
|
||||
|
||||
Easily deploy your Next.js app with [Vercel](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=github&utm_campaign=next-enterprise) by clicking the button below:
|
||||
|
||||
[](https://vercel.com/new/git/external?repository-url=https://github.com/Blazity/next-enterprise)
|
||||
|
||||
## 📃 Scripts Overview
|
||||
|
||||
The following scripts are available in the `package.json`:
|
||||
|
||||
- `dev`: Starts the development server with colorized output
|
||||
- `build`: Builds the app for production
|
||||
- `start`: Starts the production server
|
||||
- `lint`: Lints the code using ESLint
|
||||
- `lint:fix`: Automatically fixes linting errors
|
||||
- `prettier`: Checks the code for proper formatting
|
||||
- `prettier:fix`: Automatically fixes formatting issues
|
||||
- `analyze`: Analyzes the bundle sizes for Client, Server and Edge environments
|
||||
- `storybook`: Starts the Storybook server
|
||||
- `build-storybook`: Builds the Storybook for deployment
|
||||
- `test`: Runs unit and integration tests
|
||||
- `e2e:headless`: Runs end-to-end tests in headless mode
|
||||
- `e2e:ui`: Runs end-to-end tests with UI
|
||||
- `format`: Formats the code with Prettier
|
||||
- `postinstall`: Applies patches to external dependencies
|
||||
- `coupling-graph`: **Generates a coupling and cohesion graph for the components**
|
||||
|
||||
## 🔗 Coupling Graph
|
||||
|
||||
The `coupling-graph` script is a useful tool that helps visualize the coupling and connections between your project's internal modules. It's built using the [Madge](https://github.com/pahen/madge) library. To generate the graph, simply run the following command:
|
||||
|
||||
```bash
|
||||
pnpm run coupling-graph
|
||||
```
|
||||
|
||||
This will create a `graph.svg` file, which contains a graphical representation of the connections between your components. You can open the file with any SVG-compatible viewer.
|
||||
|
||||

|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
This boilerplate comes with various testing setups to ensure your application's reliability and robustness.
|
||||
|
||||
### Running Tests
|
||||
|
||||
- **Unit and integration tests**: Run Jest tests using `pnpm run test`
|
||||
- **End-to-end tests (headless mode)**: Run Playwright tests in headless mode with `pnpm run e2e:headless`
|
||||
- **End-to-end tests (UI mode)**: Run Playwright tests with UI using `pnpm run e2e:ui`
|
||||
|
||||
<img width="1392" alt="image" src="https://user-images.githubusercontent.com/28964599/233666655-93b7d08b-2fd8-406a-b43c-44d4d96cf387.png">
|
||||
|
||||
### Acceptance Tests
|
||||
|
||||
To write acceptance tests, we leverage Storybook's [`play` function](https://storybook.js.org/docs/react/writing-stories/play-function#writing-stories-with-the-play-function). This allows you to interact with your components and test various user flows within Storybook.
|
||||
|
||||
```ts
|
||||
/*
|
||||
* See https://storybook.js.org/docs/react/writing-stories/play-function#working-with-the-canvas
|
||||
* to learn more about using the canvasElement to query the DOM
|
||||
*/
|
||||
export const FilledForm: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement)
|
||||
|
||||
const emailInput = canvas.getByLabelText("email", {
|
||||
selector: "input",
|
||||
})
|
||||
|
||||
await userEvent.type(emailInput, "example-email@email.com", {
|
||||
delay: 100,
|
||||
})
|
||||
|
||||
const passwordInput = canvas.getByLabelText("password", {
|
||||
selector: "input",
|
||||
})
|
||||
|
||||
await userEvent.type(passwordInput, "ExamplePassword", {
|
||||
delay: 100,
|
||||
})
|
||||
// See https://storybook.js.org/docs/react/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel
|
||||
const submitButton = canvas.getByRole("button")
|
||||
|
||||
await userEvent.click(submitButton)
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Smoke Testing
|
||||
|
||||
In this boilerplate, we use Storybook's out-of-the-box support for smoke testing to verify that components render correctly without any errors. Just run `pnpm run test-storybook` to perform smoke testing. Remember to write stories in JSX or TSX format only. Smoke testing and a lot of other functionalities dont work well with MDX stories.
|
||||
|
||||
## 🎨 Styling and Design System
|
||||
|
||||
This boilerplate uses Tailwind CSS for styling and CVA for creating a powerful, easy-to-use design system. If you want to learn more about the setup, check out this fantastic video by Vercel:
|
||||
|
||||
[](https://www.youtube.com/watch?v=T-Zv73yZ_QI&ab_channel=Vercel)
|
||||
|
||||
### CVA - A New Approach to Variants
|
||||
|
||||
While CSS-in-TS libraries such as [Stitches](https://stitches.dev/) and [Vanilla Extract](https://vanilla-extract.style/) are great for building type-safe UI components, they might not be the perfect fit for everyone. You may prefer more control over your stylesheets, need to use a framework like Tailwind CSS, or simply enjoy writing your own CSS.
|
||||
|
||||
Creating variants using traditional CSS can be a tedious task, requiring you to manually match classes to props and add types. CVA is here to take that pain away, allowing you to focus on the enjoyable aspects of UI development. By providing an easy and type-safe way to create variants, CVA simplifies the process and helps you create powerful design systems without compromising on the flexibility and control of CSS.
|
||||
|
||||
## 💾 State Management
|
||||
|
||||
While this boilerplate doesn't include a specific state management library, we believe it's essential for you to choose the one that best suits your project's needs. Here are some libraries we recommend for state management:
|
||||
|
||||
### Zustand
|
||||
|
||||
[Zustand](https://github.com/pmndrs/zustand) is a small, fast, and scalable state management library. It's designed to be simple and intuitive, making it a great choice for small to medium-sized projects. It's also optimized for bundle size, ensuring minimal impact on your app's performance.
|
||||
|
||||
### Jotai
|
||||
|
||||
[Jotai](https://github.com/pmndrs/jotai) is an atom-based state management library for React that focuses on providing a minimal and straightforward API. Its atom-based approach allows you to manage your state in a granular way while still being highly optimized for bundle size.
|
||||
|
||||
### Recoil
|
||||
|
||||
[Recoil](https://recoiljs.org/) is a state management library developed by Facebook, specifically designed for React applications. By utilizing atoms and selectors, Recoil allows you to efficiently manage state and derived state. Its key benefit is the ability to update components only when the state they're subscribed to changes, reducing unnecessary re-renders and keeping your application fast and efficient. Recoil also offers great developer experience with built-in debugging tools.
|
||||
|
||||
Choose the library that best fits your requirements and project structure to ensure an efficient state management solution for your application.
|
||||
|
||||
## 💻 Environment Variables handling
|
||||
|
||||
[T3 Env](https://env.t3.gg/) is a library that provides environmental variables checking at build time, type validation and transforming. It ensures that your application is using the correct environment variables and their values are of the expected type. You’ll never again struggle with runtime errors caused by incorrect environment variable usage.
|
||||
|
||||
Config file is located at `env.mjs`. Simply set your client and server variables and import `env` from any file in your project.
|
||||
|
||||
```ts
|
||||
export const env = createEnv({
|
||||
server: {
|
||||
// Server variables
|
||||
SECRET_KEY: z.string(),
|
||||
},
|
||||
client: {
|
||||
// Client variables
|
||||
API_URL: z.string().url(),
|
||||
},
|
||||
runtimeEnv: {
|
||||
// Assign runtime variables
|
||||
SECRET_KEY: process.env.SECRET_KEY,
|
||||
API_URL: process.env.NEXT_PUBLIC_API_URL,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
If the required environment variables are not set, you'll get an error message:
|
||||
|
||||
```sh
|
||||
❌ Invalid environment variables: { SECRET_KEY: [ 'Required' ] }
|
||||
```
|
||||
|
||||
## 🤝 Contribution
|
||||
|
||||
Contributions are always welcome! To contribute, please follow these steps:
|
||||
|
||||
1. Fork the repository.
|
||||
2. Create a new branch with a descriptive name.
|
||||
3. Make your changes, and commit them using the [Conventional Commits](https://www.conventionalcommits.org/) format.
|
||||
4. Push your changes to the forked repository.
|
||||
5. Create a pull request, and we'll review your changes.
|
||||
|
||||
## Support
|
||||
|
||||
If you're looking for help or simply want to share your thoughts about the project, we encourage you to join our Discord community. Here's the link: [https://blazity.com/discord](https://blazity.com/discord). It's a space where we exchange ideas and help one another. Everyone's input is appreciated, and we look forward to welcoming you.
|
||||
|
||||
<br />
|
||||
<a href="https://discord.gg/fyWtyNKmfX" style="width: 100%; display: flex; justify-content: center;">
|
||||
<img src="https://discordapp.com/api/guilds/1111676875782234175/widget.png?style=banner2" alt="Blazity Discord Banner"/>
|
||||
</a>
|
||||
<br />
|
||||
|
||||
|
||||
## 📜 License
|
||||
|
||||
This project is licensed under the MIT License. For more information, see the [LICENSE](./LICENSE) file.
|
||||
|
||||
## Contributors
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://bstefanski.com/"><img src="https://avatars.githubusercontent.com/u/28964599?v=4?s=100" width="100px;" alt="Bart Stefanski"/><br /><sub><b>Bart Stefanski</b></sub></a><br /><a href="https://github.com/Blazity/next-enterprise/commits?author=bmstefanski" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jjablonski-it"><img src="https://avatars.githubusercontent.com/u/51968772?v=4?s=100" width="100px;" alt="Jakub Jabłoński"/><br /><sub><b>Jakub Jabłoński</b></sub></a><br /><a href="#infra-jjablonski-it" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://neg4n.dev/"><img src="https://avatars.githubusercontent.com/u/57688858?v=4?s=100" width="100px;" alt="Igor Klepacki"/><br /><sub><b>Igor Klepacki</b></sub></a><br /><a href="https://github.com/Blazity/next-enterprise/commits?author=neg4n" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td align="center" size="13px" colspan="7">
|
||||
<img src="https://raw.githubusercontent.com/all-contributors/all-contributors-cli/1b8533af435da9854653492b1327a23a4dbd0a10/assets/logo-small.svg">
|
||||
<a href="https://all-contributors.js.org/docs/en/bot/usage">Add your contributions</a>
|
||||
</img>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
<!-- Badges and links -->
|
||||
|
||||
[check-workflow-badge]: https://img.shields.io/github/actions/workflow/status/blazity/next-enterprise/check.yml?label=check
|
||||
[github-license-badge]: https://img.shields.io/github/license/blazity/next-enterprise?link=https%3A%2F%2Fgithub.com%2FBlazity%2Fnext-enterprise%2Fblob%2Fmain%2FLICENSE
|
||||
[github-contributors-badge]: https://img.shields.io/github/contributors/blazity/next-enterprise?link=https%3A%2F%2Fgithub.com%2FBlazity%2Fnext-enterprise%2Fgraphs%2Fcontributors
|
||||
[discord-badge]: https://img.shields.io/discord/1111676875782234175?color=7b8dcd&link=https%3A%2F%2Fblazity.com%2Fdiscord
|
||||
[made-by-blazity-badge]: https://img.shields.io/badge/made_by-Blazity-blue?color=FF782B&link=https://blazity.com/
|
||||
|
||||
[check-workflow-badge-link]: https://github.com/Blazity/next-enterprise/actions/workflows/check.yml
|
||||
[github-license-badge-link]: https://github.com/Blazity/next-enterprise/blob/main/LICENSE
|
||||
[github-contributors-badge-link]: https://github.com/Blazity/next-enterprise/graphs/contributors
|
||||
[discord-badge-link]: https://blazity.com/discord
|
||||
[made-by-blazity-badge-link]: https://blazity.com/?utm_source=nextenterprise&utm_medium=github
|
||||
1. โครงสร้างไฟล์หลักและการจัดเก็บรูปภาพ
|
||||
1.1โฟลเดอร์ app/:
|
||||
เป็นโครงสร้างพื้นฐานของ Next.js 15
|
||||
มีไฟล์หลักเช่น layout.tsx, page.tsx, และโฟลเดอร์ย่อยต่าง ๆ
|
||||
1.2โฟลเดอร์ app/assets/:
|
||||
เก็บไฟล์รูปภาพทั้งหมด เช่น image.png, image2.png, image3.png, ฯลฯ
|
||||
แนะนำให้ย้ายไปไว้ใน /public/assets/ เพื่อให้ Next.js สามารถเรียกใช้งานได้สะดวก (ถ้าเป็นการแสดงรูป Static)
|
||||
1.3โฟลเดอร์ components/:
|
||||
เก็บคอมโพเนนต์ย่อย ๆ ของโปรเจกต์ เช่น Navbar.tsx, HeroSection.tsx, หรืออื่น ๆ
|
||||
ในตัวอย่าง เรารวมโค้ดทั้งหมดไว้ในคอมโพเนนต์เดียว (เช่น page.tsx) แต่ในงานจริงอาจแยกแต่ละ Section ออกเป็นไฟล์คอมโพเนนต์ต่างหากเพื่อให้ง่ายต่อการดูแล
|
||||
|
||||
2. ขั้นตอนการติดตั้งและรันโปรเจกต์
|
||||
2.1ติดตั้ง Dependencies
|
||||
ใช้คำสั่ง npm install หรือ yarn เพื่อให้ได้ package ของ Next.js, React, และ Tailwind CSS
|
||||
2.2ตั้งค่า Tailwind CSS
|
||||
เปิดไฟล์ tailwind.config.js (หรือ .ts) แล้วกำหนด content ให้ครอบคลุมทุกไฟล์ที่มีการใช้งาน Tailwind เช่น
|
||||
content: [
|
||||
"./app/**/*.{js,ts,jsx,tsx}",
|
||||
"./components/**/*.{js,ts,jsx,tsx}",
|
||||
...
|
||||
]
|
||||
2.3รันโปรเจกต์
|
||||
ใช้คำสั่ง npm run dev หรือ yarn dev
|
||||
เปิดเบราว์เซอร์ที่ http://localhost:3000 เพื่อดูหน้าเว็บ
|
||||
|
||||
3. สรุปการทำงานของแต่ละส่วน
|
||||
โค้ดหลักแบ่งออกเป็นหลาย Section ตามโครงสร้างเว็บ ดังนี้:
|
||||
|
||||
3.1Top Announcement Bar
|
||||
แถบสีเขียวเข้มด้านบน (เช่น #0e3a24)
|
||||
มีข้อความประกาศ เช่น "SupportNinja is hiring! …" พร้อมลิงก์สมัครงาน
|
||||
|
||||
3.2Navbar (Sticky) + Dropdown & Hamburger
|
||||
ติดด้านบน (sticky top-0)
|
||||
มีโลโก้ซ้ายมือ, เมนูขวามือ (Desktop), ปุ่ม Get Started
|
||||
Dropdown Menu: เมื่อ Hover เมนูอย่าง Solutions, Industries, About จะมีเมนูย่อยแสดงขึ้นมา (ใช้ useState แยกแต่ละเมนู)
|
||||
Hamburger Menu (Mobile): เมื่อจอเล็ก (< md) จะแทนที่เมนูด้วยปุ่ม Hamburger (เปิด/ปิดเมนูด้วย isMobileMenuOpen)
|
||||
ภายในเมนู Mobile มีปุ่ม Get Started อีกอันด้านล่าง
|
||||
|
||||
3.3Hero Section
|
||||
พื้นหลังสีครีม (เช่น #f7e1d2)
|
||||
ข้อความสั้น ๆ และหัวข้อใหญ่ เช่น "Outsourcing worth talking about"
|
||||
มีเส้น <hr> คั่น
|
||||
|
||||
3.4Outsourcing Options Section (Checkbox Grid)
|
||||
ยังใช้พื้นหลังสีครีม (#f7e1d2)
|
||||
หัวข้อ "Which outsourcing solutions are you looking for?"
|
||||
มี Grid 6 ช่อง แต่ละช่องมีรูป (เช่น image2.png), ชื่อบริการ, และ Checkbox ที่มุมขวาบน
|
||||
เมื่อคลิกช่องใด จะสลับสถานะ Checkbox และเปลี่ยนพื้นหลังของช่อง (ใช้ useState ชื่อ selected)
|
||||
ด้านล่างมีปุ่ม Get Started สีแดง
|
||||
|
||||
3.5Section เพิ่มเติม (1 → 6)
|
||||
แต่ละ Section มีดีไซน์แตกต่างกัน เช่น พื้นหลังสีต่าง ๆ, รูปซ้าย-ข้อความขวา หรือข้อความซ้าย-รูปขวา
|
||||
Section 1: ใส่ Container สีเทา (#bfc1b9) ข้างใน พร้อมรูป midjourney.png
|
||||
Section 2, 3, 4, 5: จัดเป็น 2 คอลัมน์ หรือ Grid 3 คอลัมน์ (เช่นบริการต่าง ๆ)
|
||||
Section 6: "We’re better together. Start building your dream team." พร้อมรูป image8.png ทางขวา, ปุ่ม Get Started สีแดง
|
||||
|
||||
3.6Footer
|
||||
พื้นหลังสีเทาอ่อน (#bfc1b9)
|
||||
มีโลโก้, คอลัมน์เมนูต่าง ๆ (Solutions, Industries, Resources, Follow, Company)
|
||||
ปุ่ม Get started สีแดงอยู่ด้านขวา
|
||||
ด้านล่างมีข้อความลิขสิทธิ์และลิงก์ (Privacy Policy, Security Policy, Terms of Use)
|
||||
ออกแบบให้ Responsive เมื่อจอเล็กจะเรียงกันเป็นคอลัมน์
|
||||
|
||||
4. การใช้ State และฟังก์ชันต่าง ๆ
|
||||
4.1State สำหรับ Dropdown
|
||||
isSolutionsOpen, isIndustriesOpen, isAboutOpen: ควบคุมการเปิด/ปิดเมนูย่อยใน Desktop
|
||||
ทำงานด้วยการ onMouseEnter → setState(true), onMouseLeave → setState(false)
|
||||
State สำหรับ Mobile Menu
|
||||
|
||||
4.2isMobileMenuOpen: เมื่อคลิกปุ่ม Hamburger จะสลับ true/false
|
||||
ถ้า true จะแสดงเมนูในรูปแบบลิสต์ลงมา
|
||||
|
||||
4.3State สำหรับ Checkbox Grid
|
||||
selected: string[]: เก็บ ID ของ Option ที่ถูกเลือก
|
||||
ฟังก์ชัน toggleSelection(id: string): เช็คว่า ID นั้นอยู่ใน selected ไหม → ถ้ามีก็ถอดออก, ถ้าไม่มีให้เพิ่มเข้า
|
||||
|
||||
4.4โครงสร้างเมนู
|
||||
ใน Desktop, เมนูหลักจะซ่อนบนจอเล็ก (ใช้ md:flex / hidden)
|
||||
ใน Mobile, เมนูหลักจะแสดงเมื่อ isMobileMenuOpen === true
|
||||
|
||||
5. เคล็ดลับการปรับแต่ง
|
||||
5.1เปลี่ยนสี / ข้อความ:
|
||||
ใน Class Tailwind เช่น bg-[#0e3a24], text-[#f7e1d2], สามารถเปลี่ยนเป็นโทนสีอื่น ๆ ได้
|
||||
ข้อความต่าง ๆ เช่น H1, H2, หรือ Paragraph แก้ได้ตามต้องการ
|
||||
|
||||
5.2เปลี่ยนรูปภาพ:
|
||||
ตรวจสอบว่ารูปอยู่ใน /public/assets/ แล้วเรียกใช้ด้วยเส้นทาง /assets/xxxx.png
|
||||
ขนาดรูป (width, height) สามารถปรับตามดีไซน์
|
||||
|
||||
5.3Responsive เพิ่มเติม:
|
||||
Tailwind มี breakpoint sm:, md:, lg:, xl: ถ้าต้องการจัด layout หรือขนาดตัวอักษรเฉพาะจอใหญ่/เล็ก
|
||||
|
||||
5.4แยกเป็นคอมโพเนนต์:
|
||||
ถ้าไฟล์ Navbar.tsx ใหญ่มาก สามารถแยกแต่ละ Section ไปเป็นไฟล์คอมโพเนนต์ย่อย แล้ว import มาใช้เพื่อความเป็นระเบียบ
|
||||
|
||||
5.5Production Build:
|
||||
เมื่อพร้อม Deploy, ให้ใช้คำสั่ง npm run build หรือ yarn build
|
||||
จากนั้น npm run start หรือ yarn start เพื่อรัน Production Mode
|
||||
|
||||
6. วิธีนำไปใช้งานจริง
|
||||
6.1คัดลอกโค้ด นี้ไปใส่ในไฟล์คอมโพเนนต์ เช่น page.tsx (หรือชื่อไฟล์ที่ต้องการ)
|
||||
6.2รัน npm run dev
|
||||
6.3เปิด http://localhost:3000
|
||||
ดูว่า Navbar, Hero, Sections และ Footer แสดงผลครบถ้วนหรือไม่
|
||||
|
||||
7. สรุป
|
||||
1.โค้ดนี้เป็นตัวอย่างหน้าเว็บ Next.js 15 + Tailwind CSS ที่มีฟีเจอร์หลัก:
|
||||
-Navbar Sticky พร้อม Dropdown (Desktop) และ Hamburger (Mobile)
|
||||
-Hero Section สีครีม
|
||||
-Grid Checkbox เลือกบริการต่าง ๆ
|
||||
-Sections หลายส่วน (ใส่รูป + ข้อความ)
|
||||
-Footer ที่แบ่งคอลัมน์ลิงก์ และมีปุ่ม Get Started สีแดง
|
||||
|
||||
###ขอบคุณครับ :)
|
||||
809
app/page.tsx
|
|
@ -1,66 +1,765 @@
|
|||
import { Metadata } from "next"
|
||||
import { Button } from "components/Button/Button"
|
||||
"use client"; // ใช้ useState และ useEffect ใน Next.js 15
|
||||
|
||||
import { LP_GRID_ITEMS } from "lp-items"
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Next.js Enterprise Boilerplate",
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
},
|
||||
openGraph: {
|
||||
url: "https://next-enterprise.vercel.app/",
|
||||
images: [
|
||||
{
|
||||
width: 1200,
|
||||
height: 630,
|
||||
url: "https://raw.githubusercontent.com/Blazity/next-enterprise/main/.github/assets/project-logo.png",
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
export default function Navbar() {
|
||||
// Dropdown State (Desktop)
|
||||
const [isSolutionsOpen, setSolutionsOpen] = useState(false);
|
||||
const [isIndustriesOpen, setIndustriesOpen] = useState(false);
|
||||
const [isAboutOpen, setAboutOpen] = useState(false);
|
||||
|
||||
// Mobile Menu State
|
||||
const [isMobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||
|
||||
// Checkbox Grid State
|
||||
const [selected, setSelected] = useState<string[]>([]);
|
||||
const options = [
|
||||
{ id: "customer-experience", label: "Customer Experience", img: "/assets/image2.png" },
|
||||
{ id: "customer-support", label: "Customer Support", img: "/assets/image2.png" },
|
||||
{ id: "technical-support", label: "Technical Customer Support", img: "/assets/image2.png" },
|
||||
{ id: "content-moderation", label: "Content Moderation", img: "/assets/image2.png" },
|
||||
{ id: "data-processing", label: "Data Processing", img: "/assets/image2.png" },
|
||||
{ id: "finance-accounting", label: "Finance & Accounting", img: "/assets/image2.png" },
|
||||
];
|
||||
|
||||
// Toggle Checkbox selection
|
||||
const toggleSelection = (id: string) => {
|
||||
setSelected((prev) =>
|
||||
prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id]
|
||||
);
|
||||
};
|
||||
|
||||
export default function Web() {
|
||||
return (
|
||||
<>
|
||||
<section className="bg-white dark:bg-gray-900">
|
||||
<div className="mx-auto grid max-w-(--breakpoint-xl) px-4 py-8 text-center lg:py-16">
|
||||
<div className="mx-auto place-self-center">
|
||||
<h1 className="mb-4 max-w-2xl text-4xl leading-none font-extrabold tracking-tight md:text-5xl xl:text-6xl dark:text-white">
|
||||
Next.js Enterprise Boilerplate
|
||||
</h1>
|
||||
<p className="mb-6 max-w-2xl font-light text-gray-500 md:text-lg lg:mb-8 lg:text-xl dark:text-gray-400">
|
||||
Jumpstart your enterprise project with our feature-packed, high-performance Next.js boilerplate!
|
||||
Experience rapid UI development, AI-powered code reviews, and an extensive suite of tools for a smooth and
|
||||
enjoyable development process.
|
||||
</p>
|
||||
<Button href="https://github.com/Blazity/next-enterprise" className="mr-3">
|
||||
Get started
|
||||
</Button>
|
||||
<Button
|
||||
href="https://vercel.com/new/git/external?repository-url=https://github.com/Blazity/next-enterprise"
|
||||
intent="secondary"
|
||||
>
|
||||
Deploy Now
|
||||
</Button>
|
||||
</div>
|
||||
<header className="w-full font-['Tenon',sans-serif]">
|
||||
{/* Top Announcement Bar */}
|
||||
<div className="bg-[#0e3a24] py-3 text-center text-sm text-[#f7e1d2]">
|
||||
SupportNinja is hiring! Apply through our Jobs Board.{" "}
|
||||
<Link href="#" className="underline text-[#f7e1d2]">
|
||||
Find Open Positions Today
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Main Navbar (Sticky) */}
|
||||
<nav className="sticky top-0 z-50 bg-[#f7e1d2] shadow-md px-4 sm:px-10 py-4 flex items-center justify-between">
|
||||
{/* Left - Logo */}
|
||||
<div className="flex items-center">
|
||||
<Image
|
||||
src="/assets/image.png"
|
||||
alt="SupportNinja Logo"
|
||||
width={200}
|
||||
height={50}
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
<section className="bg-white dark:bg-gray-900">
|
||||
<div className="mx-auto max-w-(--breakpoint-xl) px-4 py-8 sm:py-16 lg:px-6">
|
||||
<div className="justify-center space-y-8 md:grid md:grid-cols-2 md:gap-12 md:space-y-0 lg:grid-cols-3">
|
||||
{LP_GRID_ITEMS.map((singleItem) => (
|
||||
<div key={singleItem.title} className="flex flex-col items-center justify-center text-center">
|
||||
<div className="bg-primary-100 dark:bg-primary-900 mb-4 flex size-10 items-center justify-center rounded-full p-1.5 text-blue-700 lg:size-12">
|
||||
{singleItem.icon}
|
||||
|
||||
{/* Hamburger Button (Mobile Only) */}
|
||||
<button
|
||||
className="flex items-center justify-center p-2 text-gray-900 rounded-md md:hidden"
|
||||
onClick={() => setMobileMenuOpen(!isMobileMenuOpen)}
|
||||
>
|
||||
{/* Icon Hamburger / Close */}
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
{isMobileMenuOpen ? (
|
||||
// X icon
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
) : (
|
||||
// Hamburger icon
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M4 6h16M4 12h16M4 18h16"
|
||||
/>
|
||||
)}
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{/* Desktop Menu */}
|
||||
<ul className="hidden space-x-8 text-lg font-medium text-gray-900 md:flex">
|
||||
{/* Solutions (Desktop Dropdown) */}
|
||||
<li
|
||||
className="relative group"
|
||||
onMouseEnter={() => setSolutionsOpen(true)}
|
||||
onMouseLeave={() => setSolutionsOpen(false)}
|
||||
>
|
||||
<button className="flex items-center space-x-1">
|
||||
<span>Solutions</span>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="18px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="18px"
|
||||
className={`transition-transform duration-300 ${
|
||||
isSolutionsOpen ? "rotate-180" : ""
|
||||
}`}
|
||||
>
|
||||
<path d="M480-333 240-573l51-51 189 189 189-189 51 51-240 240Z" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{/* Dropdown Solutions */}
|
||||
{isSolutionsOpen && (
|
||||
<div className="absolute left-0 z-50 p-4 mt-3 bg-white border border-gray-300 rounded-lg shadow-lg w-80">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<h3 className="font-semibold text-gray-900">Customer Experience</h3>
|
||||
<ul className="mt-2 space-y-2 text-sm text-gray-700">
|
||||
<li><Link href="#">Customer Conversion</Link></li>
|
||||
<li><Link href="#">Customer Onboarding</Link></li>
|
||||
<li><Link href="#">Customer Support</Link></li>
|
||||
<li><Link href="#">Technical Support</Link></li>
|
||||
<li><Link href="#">Customer Renewals</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-semibold text-gray-900">Finance & Accounting</h3>
|
||||
<h3 className="mt-3 font-semibold text-gray-900">Content Moderation</h3>
|
||||
<h3 className="mt-3 font-semibold text-gray-900">Data Processing</h3>
|
||||
</div>
|
||||
</div>
|
||||
<h3 className="mb-2 text-xl font-bold dark:text-white">{singleItem.title}</h3>
|
||||
<p className="text-gray-500 dark:text-gray-400">{singleItem.description}</p>
|
||||
</div>
|
||||
))}
|
||||
)}
|
||||
</li>
|
||||
|
||||
{/* Industries (Desktop Dropdown) */}
|
||||
<li
|
||||
className="relative group"
|
||||
onMouseEnter={() => setIndustriesOpen(true)}
|
||||
onMouseLeave={() => setIndustriesOpen(false)}
|
||||
>
|
||||
<button className="flex items-center space-x-1">
|
||||
<span>Industries</span>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="18px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="18px"
|
||||
className={`transition-transform duration-300 ${
|
||||
isIndustriesOpen ? "rotate-180" : ""
|
||||
}`}
|
||||
>
|
||||
<path d="M480-333 240-573l51-51 189 189 189-189 51 51-240 240Z" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{/* Dropdown Industries */}
|
||||
{isIndustriesOpen && (
|
||||
<div className="absolute left-0 z-50 mt-3 w-[400px] rounded-lg border border-gray-300 bg-white p-4 shadow-lg">
|
||||
<div className="grid grid-cols-3 gap-6 font-medium text-gray-900">
|
||||
<span>SaaS</span>
|
||||
<span>AI</span>
|
||||
<span>Ecommerce</span>
|
||||
<span>Healthcare</span>
|
||||
<span>Supply Chain & Logistics</span>
|
||||
<span>Fintech</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</li>
|
||||
|
||||
<li><Link href="#">How it Works</Link></li>
|
||||
|
||||
{/* About (Desktop Dropdown) */}
|
||||
<li
|
||||
className="relative group"
|
||||
onMouseEnter={() => setAboutOpen(true)}
|
||||
onMouseLeave={() => setAboutOpen(false)}
|
||||
>
|
||||
<button className="flex items-center space-x-1">
|
||||
<span>About</span>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="18px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="18px"
|
||||
className={`transition-transform duration-300 ${
|
||||
isAboutOpen ? "rotate-180" : ""
|
||||
}`}
|
||||
>
|
||||
<path d="M480-333 240-573l51-51 189 189 189-189 51 51-240 240Z" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{/* Dropdown About */}
|
||||
{isAboutOpen && (
|
||||
<div className="absolute left-0 z-50 w-40 p-3 mt-3 bg-white border border-gray-300 rounded-lg shadow-lg">
|
||||
<ul className="space-y-2 text-gray-900">
|
||||
<li className="flex justify-between">
|
||||
<Link href="#">About us</Link>
|
||||
</li>
|
||||
<hr />
|
||||
<li className="flex justify-between">
|
||||
<Link href="#">Careers</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</li>
|
||||
|
||||
<li><Link href="#">Resources</Link></li>
|
||||
</ul>
|
||||
|
||||
{/* Desktop - Get Started Button */}
|
||||
<Link
|
||||
href="#"
|
||||
className="hidden md:inline-flex bg-[#0e3a24] text-white px-6 py-2 text-lg rounded-full font-semibold hover:bg-[#0b2d1d] transition"
|
||||
>
|
||||
Get Started
|
||||
</Link>
|
||||
</nav>
|
||||
|
||||
{/* Mobile Menu (Slide Down) */}
|
||||
{isMobileMenuOpen && (
|
||||
<div className="md:hidden bg-[#f7e1d2] shadow-md px-4 pb-4">
|
||||
<ul className="flex flex-col mt-4 space-y-4 text-lg font-medium text-gray-900">
|
||||
<li><Link href="#" className="block">Solutions</Link></li>
|
||||
<li><Link href="#" className="block">Industries</Link></li>
|
||||
<li><Link href="#" className="block">How it Works</Link></li>
|
||||
<li><Link href="#" className="block">About</Link></li>
|
||||
<li><Link href="#" className="block">Resources</Link></li>
|
||||
</ul>
|
||||
|
||||
{/* Mobile - Get Started Button */}
|
||||
<div className="mt-4">
|
||||
<Link
|
||||
href="#"
|
||||
className="inline-flex w-full justify-center bg-[#0e3a24] text-white px-6 py-3 text-lg rounded-full font-semibold hover:bg-[#0b2d1d] transition"
|
||||
>
|
||||
Get Started
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Hero Section */}
|
||||
<section className="bg-[#f7e1d2] py-24 text-center">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<p className="text-lg text-gray-700">
|
||||
Quickly and seamlessly scale your team with agile, highly customizable outsourcing solutions that power your growth.
|
||||
</p>
|
||||
<h1 className="mt-6 text-6xl font-bold text-gray-900">
|
||||
Outsourcing worth talking about
|
||||
</h1>
|
||||
<hr className="w-1/2 mx-auto mt-6 border-gray-400" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Outsourcing Options Section */}
|
||||
<section className="bg-[#f7e1d2] py-16 text-center">
|
||||
<h2 className="text-2xl font-semibold text-gray-900">
|
||||
Which outsourcing solutions are you looking for?
|
||||
</h2>
|
||||
<p className="text-gray-600">Choose as many as you need.</p>
|
||||
|
||||
{/* Options Grid */}
|
||||
<div className="grid grid-cols-1 gap-4 px-10 mt-8 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-6">
|
||||
{options.map((option) => (
|
||||
<div
|
||||
key={option.id}
|
||||
className={`relative p-4 rounded-lg shadow-md transition-all duration-300 cursor-pointer flex flex-col items-center justify-center ${
|
||||
selected.includes(option.id) ? "bg-white border-2 border-gray-300" : "bg-[#fbeee6]"
|
||||
}`}
|
||||
onClick={() => toggleSelection(option.id)}
|
||||
>
|
||||
{/* Checkbox */}
|
||||
<div className="absolute top-3 right-3">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selected.includes(option.id)}
|
||||
onChange={() => toggleSelection(option.id)}
|
||||
className="appearance-none w-5 h-5 border border-gray-500 rounded-md checked:bg-black checked:border-transparent checked:before:content-['✔'] checked:before:text-white checked:before:text-xs flex items-center justify-center transition-all duration-300"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Image & Text */}
|
||||
<Image src={option.img} alt={option.label} width={80} height={80} className="mb-3" />
|
||||
<h3 className="mt-2 font-semibold text-center">{option.label}</h3>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Get Started Button */}
|
||||
<div className="flex justify-center mt-8">
|
||||
<Link
|
||||
href="#"
|
||||
className="inline-flex items-center px-6 py-3 text-lg font-semibold text-white transition bg-red-600 rounded-full hover:bg-red-700"
|
||||
>
|
||||
Get Started
|
||||
<span className="inline-flex items-center justify-center w-8 h-8 ml-2 bg-white rounded-full">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#D32F2F">
|
||||
<path d="m600-216-51-51 177-177H96v-72h630L549-693l51-51 264 264-264 264Z"/>
|
||||
</svg>
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ----------------------------- NEW SECTIONS ----------------------------- */}
|
||||
|
||||
{/* SECTION 1: bg #bfc1b9 + midjourney.png */}
|
||||
<section className="bg-[#f7e1d2] py-16 text-center">
|
||||
<div className="max-w-6xl mx-auto bg-[#bfc1b9] rounded-lg px-6 py-8 flex flex-col md:flex-row items-center justify-between">
|
||||
<h2 className="mb-4 text-2xl font-semibold text-gray-900 md:mb-0">
|
||||
Driving better business results for 200+ companies.
|
||||
</h2>
|
||||
<div>
|
||||
<Image
|
||||
src="/assets/midjourney.png"
|
||||
alt="Midjourney Logo"
|
||||
width={150}
|
||||
height={50}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
)
|
||||
|
||||
{/* SECTION 2: bg-white + image2.png + เนื้อหา 2 คอลัมน์ (ข้อความซ้าย, รูปขวา) */}
|
||||
<section className="py-16 bg-white">
|
||||
|
||||
<div className="max-w-6xl px-4 mx-auto md:grid md:grid-cols-2 md:gap-8 md:items-center">
|
||||
<div className="flex justify-center mt-8 md:mt-0">
|
||||
<Image
|
||||
src="/assets/image3.png"
|
||||
alt="Scale Up"
|
||||
width={400}
|
||||
height={400}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="mb-4 text-4xl font-bold text-gray-900">
|
||||
Free up resources, accelerate growth, and solve for scale.
|
||||
</h2>
|
||||
<p className="mb-4 text-gray-700">
|
||||
At SupportNinja, we combine cutting-edge technology with value-centricity to foster high-performing, reliable teams that turn growing pains into efficient pathways to profitability.
|
||||
</p>
|
||||
<p className="mb-4 text-gray-700">
|
||||
Our customized, agile, AI-enabled solutions don’t just deliver cost savings — they also keep key business outcomes front and center.
|
||||
</p>
|
||||
<p className="text-gray-700">
|
||||
We work closely with you to continually adjust strategies, realize efficiencies, and drive scaling according to your unique needs. Plus, flexibility is baked in so you’re never locked into rigid, long-term contracts.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* SECTION 3: bg-white + image3.png + เนื้อหา (Don't grow it alone) */}
|
||||
<section className="py-16 bg-white">
|
||||
<div className="max-w-6xl px-4 mx-auto md:grid md:grid-cols-2 md:gap-8 md:items-center">
|
||||
<div>
|
||||
<h2 className="mb-4 text-4xl font-bold text-gray-900">
|
||||
Don’t grow it alone
|
||||
</h2>
|
||||
<p className="mb-4 text-gray-700">
|
||||
Don’t let headcount become a headache. We’ll connect you with talent that meets your needs.
|
||||
</p>
|
||||
<p className="text-gray-700">
|
||||
Your dedicated new team members will become experts in your world — your customers, your tech, your data, your systems — so they can expand on what you’ve built.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex justify-center mt-8 md:mt-0">
|
||||
<Image
|
||||
src="/assets/image4.png"
|
||||
alt="Grow Together"
|
||||
width={200}
|
||||
height={200}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{/* SECTION 4 */}
|
||||
<section className="py-16 bg-white">
|
||||
<div className="max-w-6xl px-4 mx-auto">
|
||||
<div className="grid grid-cols-1 gap-8 md:grid-cols-2 lg:grid-cols-3">
|
||||
{/* Customer Support */}
|
||||
<div className="p-6 bg-white rounded-lg shadow-md">
|
||||
<div className="flex items-center mb-3">
|
||||
{/* Icon (No Background, Enlarged, #2b2c30) */}
|
||||
<span className="inline-flex items-center justify-center w-10 h-10 mr-3">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
width="24px"
|
||||
fill="#2b2c30"
|
||||
viewBox="0 -960 960 960"
|
||||
>
|
||||
<path d="M432-144v-72h312v-267q0-110-76.78-187.5t-187-77.5Q370-748 293-670.5T216-483v227h-48q-29.7 0-50.85-21.74Q96-299.48 96-330v-74q0-23 13-41t35-23l3-51q9-63 38-117.5t73.5-94.5q44.5-40 101.49-62.5 56.99-22.5 120-22.5t119.81 22.56q56.81 22.55 101.5 62.5Q746-691 775-637t38 117l3 52q21 5 34.5 21.5T864-408v84q0 22-13.5 38.5T816-264v48q0 29.7-21.15 50.85Q773.7-144 744-144H432Zm-59.79-264q-15.21 0-25.71-10.29t-10.5-25.5q0-15.21 10.29-25.71t25.5-10.5q15.21 0 25.71 10.29t10.5 25.5q0 15.21-10.29 25.71t-25.5 10.5Zm216 0q-15.21 0-25.71-10.29t-10.5-25.5q0-15.21 10.29-25.71t25.5-10.5q15.21 0 25.71 10.29t10.5 25.5q0 15.21-10.29 25.71t-25.5 10.5ZM265-458q-9-97 55.7-167.5T482-696q82 0 142.5 55T694-504q-85 0-154.5-46.5T432-672q-14 71-57.5 127.5T265-458Z"/>
|
||||
</svg>
|
||||
</span>
|
||||
<h3 className="text-xl font-semibold text-[#2b2c30]">Customer Support</h3>
|
||||
</div>
|
||||
<p className="text-[#2b2c30] mb-4">
|
||||
Transform every interaction into a positive experience with customer-centric support that scales as you grow.
|
||||
</p>
|
||||
<Link href="#" className="font-semibold text-[#2b2c30] hover:underline">
|
||||
Explore Customer Support →
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Customer Experience */}
|
||||
<div className="p-6 bg-white rounded-lg shadow-md">
|
||||
<div className="flex items-center mb-3">
|
||||
<span className="inline-flex items-center justify-center w-10 h-10 mr-3">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
width="24px"
|
||||
fill="#2b2c30"
|
||||
viewBox="0 -960 960 960"
|
||||
>
|
||||
<path d="m347-72-75-124-141-32 13-144-96-108 96-108-13-144 141-32 75-124 133 57 133-57 75 124 141 32-13 144 96 108-96 108 13 144-141 32-75 124-133-57-133 57Zm29-91 104-44 104 44 58-97 110-25-10-111 74-84-74-84 10-111-110-25-58-97-104 44-104-44-58 97-110 24 10 112-74 84 75 84-11 112 110 25 58 96Zm104-317Zm-51 144 238-237-51-51-187 186-85-84-51 51 136 135Z"/>
|
||||
</svg>
|
||||
</span>
|
||||
<h3 className="text-xl font-semibold text-[#2b2c30]">Customer Experience</h3>
|
||||
</div>
|
||||
<p className="text-[#2b2c30] mb-4">
|
||||
Enhance every stage of your customer journey and scale confidently — from a simple touchpoint to the entire lifecycle.
|
||||
</p>
|
||||
<Link href="#" className="font-semibold text-[#2b2c30] hover:underline">
|
||||
Explore Customer Experience →
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Technical Customer Support */}
|
||||
<div className="p-6 bg-white rounded-lg shadow-md">
|
||||
<div className="flex items-center mb-3">
|
||||
<span className="inline-flex items-center justify-center w-10 h-10 mr-3">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
width="24px"
|
||||
fill="#2b2c30"
|
||||
viewBox="0 -960 960 960"
|
||||
>
|
||||
<path d="M48-144v-72h864v72H48Zm120-120q-29.7 0-50.85-21.15Q96-306.3 96-336v-408q0-29.7 21.15-50.85Q138.3-816 168-816h624q29.7 0 50.85 21.15Q864-773.7 864-744v408q0 29.7-21.15 50.85Q821.7-264 792-264H168Zm0-72h624v-408H168v408Zm0 0v-408 408Z"/>
|
||||
</svg>
|
||||
</span>
|
||||
<h3 className="text-xl font-semibold text-[#2b2c30]">Technical Customer Support</h3>
|
||||
</div>
|
||||
<p className="text-[#2b2c30] mb-4">
|
||||
Outsourced dedicated experts on your business to answer customer questions in detail.
|
||||
</p>
|
||||
<Link href="#" className="font-semibold text-[#2b2c30] hover:underline">
|
||||
Explore Technical Customer Support →
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Content Moderation */}
|
||||
<div className="p-6 bg-white rounded-lg shadow-md">
|
||||
<div className="flex items-center mb-3">
|
||||
<span className="inline-flex items-center justify-center w-10 h-10 mr-3">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
width="24px"
|
||||
fill="#2b2c30"
|
||||
viewBox="0 -960 960 960"
|
||||
>
|
||||
<path d="M216-216h51l375-375-51-51-375 375v51Zm-72 72v-153l498-498q11-11 23.84-16 12.83-5 27-5 14.16 0 27.16 5t24 16l51 51q11 11 16 24t5 26.54q0 14.45-5.02 27.54T795-642L297-144H144Zm600-549-51-51 51 51Zm-127.95 76.95L591-642l51 51-25.95-25.05Z"/>
|
||||
</svg>
|
||||
</span>
|
||||
<h3 className="text-xl font-semibold text-[#2b2c30]">Content Moderation</h3>
|
||||
</div>
|
||||
<p className="text-[#2b2c30] mb-4">
|
||||
Build a thriving online presence with a team specially trained to uphold your community standards.
|
||||
</p>
|
||||
<Link href="#" className="font-semibold text-[#2b2c30] hover:underline">
|
||||
Explore Content Moderation →
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Data Processing */}
|
||||
<div className="p-6 bg-white rounded-lg shadow-md">
|
||||
<div className="flex items-center mb-3">
|
||||
<span className="inline-flex items-center justify-center w-10 h-10 mr-3">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
width="24px"
|
||||
fill="#2b2c30"
|
||||
viewBox="0 -960 960 960"
|
||||
>
|
||||
<path d="m403-96-22-114q-23-9-44.5-21T296-259l-110 37-77-133 87-76q-2-12-3-24t-1-25q0-13 1-25t3-24l-87-76 77-133 110 37q19-16 40.5-28t44.5-21l22-114h154l22 114q23 9 44.5 21t40.5 28l110-37 77 133-87 76q2 12 3 24t1 25q0 13-1 25t-3 24l87 76-77 133-110-37q-19 16-40.5 28T579-210L557-96H403Zm59-72h36l19-99q38-7 71-26t57-48l96 32 18-30-76-67q6-17 9.5-35.5T696-480q0-20-3.5-38.5T683-554l76-67-18-30-96 32q-24-29-57-48t-71-26l-19-99h-36l-19 99q-38 7-71 26t-57 48l-96-32-18 30 76 67q-6 17-9.5 35.5T264-480q0 20 3.5 38.5T277-406l-76 67 18 30 96-32q24 29 57 48t71 26l19 99Zm18-168q60 0 102-42t42-102q0-60-42-102t-102-42q-60 0-102 42t-42 102q0 60 42 102t102 42Zm0-144Z"/>
|
||||
</svg>
|
||||
</span>
|
||||
<h3 className="text-xl font-semibold text-[#2b2c30]">Data Processing</h3>
|
||||
</div>
|
||||
<p className="text-[#2b2c30] mb-4">
|
||||
Receive analyzed data, specific to how you need it interpreted and presented.
|
||||
</p>
|
||||
<Link href="#" className="font-semibold text-[#2b2c30] hover:underline">
|
||||
Explore Data Processing →
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Finance & Accounting */}
|
||||
<div className="p-6 bg-white rounded-lg shadow-md">
|
||||
<div className="flex items-center mb-3">
|
||||
<span className="inline-flex items-center justify-center w-10 h-10 mr-3">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
width="24px"
|
||||
fill="#2b2c30"
|
||||
viewBox="0 -960 960 960"
|
||||
>
|
||||
<path d="M446-216h67v-47q49-8 81-42t32-79q0-45-27.5-77T514-514q-61-22-80.5-37.5T414-592q0-20 17.5-33t45.5-13q28 0 49 13.5t28 36.5l59-25q-12-33-38.5-55.5T513-697v-47h-66v48q-45 10-72 38.5T348-591q0 45 30.5 76.5T475-460q45 16 65.5 34t20.5 42q0 26-21 43.5T488-323q-33 0-58.5-22T395-402l-62 26q12 42 42 71.5t71 40.5v48Zm34 120q-79 0-149-30t-122.5-82.5Q156-261 126-331T96-480q0-80 30-149.5t82.5-122Q261-804 331-834t149-30q80 0 149.5 30t122 82.5Q804-699 834-629.5T864-480q0 79-30 149t-82.5 122.5Q699-156 629.5-126T480-96Zm0-72q130 0 221-91t91-221q0-130-91-221t-221-91q-130 0-221 91t-91 221q0 130 91 221t221 91Zm0-312Z"/>
|
||||
</svg>
|
||||
</span>
|
||||
<h3 className="text-xl font-semibold text-[#2b2c30]">Finance & Accounting</h3>
|
||||
</div>
|
||||
<p className="text-[#2b2c30] mb-4">
|
||||
Streamline your financial operations with expert accounting and bookkeeping services.
|
||||
</p>
|
||||
<Link href="#" className="font-semibold text-[#2b2c30] hover:underline">
|
||||
Explore Finance & Accounting →
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
{/* SECTION 5 */}
|
||||
<section className="py-16 bg-white">
|
||||
<div className="max-w-6xl px-4 mx-auto">
|
||||
{/* Row 1: Images Left, Text Right */}
|
||||
<div className="md:grid md:grid-cols-2 md:gap-8 md:items-center">
|
||||
{/* Images (Left) */}
|
||||
<div className="flex justify-center mb-8 md:mb-0">
|
||||
{/* คุณอาจจัดวาง image5, image6 ซ้อนกัน หรือวางเคียงกันได้ตามต้องการ */}
|
||||
|
||||
{/* Text (Right) */}
|
||||
<div>
|
||||
<h2 className="mb-4 text-3xl font-bold text-gray-900">
|
||||
We’re passionate about our people.
|
||||
</h2>
|
||||
<p className="mb-4 text-gray-700">
|
||||
Our people-first culture attracts and retains top talent...
|
||||
</p>
|
||||
<p className="mb-6 text-gray-700">
|
||||
For nearly a decade, we’ve fostered the growth, wellbeing, and career development
|
||||
of our team members — and that’s earned us industry-high talent retention rates.
|
||||
</p>
|
||||
<Link
|
||||
href="#"
|
||||
className="inline-block px-6 py-3 rounded-full bg-[#0e3a24] text-white font-semibold hover:bg-[#0b2d1d] transition"
|
||||
>
|
||||
Read our story
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="relative w-fit">
|
||||
<Image
|
||||
src="/assets/image5.png"
|
||||
alt="Image 5"
|
||||
width={500}
|
||||
height={500}
|
||||
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-16 bg-white">
|
||||
<div className="max-w-6xl px-4 mx-auto">
|
||||
{/* Row 2: Text Left, Image Right */}
|
||||
<div className="md:grid md:grid-cols-2 md:gap-8 md:items-center">
|
||||
{/* Text (Left) */}
|
||||
|
||||
{/* Image (Right) */}
|
||||
<div className="flex justify-center mt-8 md:mt-0">
|
||||
<Image
|
||||
src="/assets/image7.png"
|
||||
alt="Image 7"
|
||||
width={700}
|
||||
height={700}
|
||||
className="rounded-lg shadow-md"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="mb-4 text-3xl font-bold text-gray-900">
|
||||
Grow your career and unleash your potential.
|
||||
</h2>
|
||||
<p className="mb-4 text-gray-700">
|
||||
Ready to expand your horizons at a truly global company?
|
||||
</p>
|
||||
<p className="mb-6 text-gray-700">
|
||||
At SupportNinja, we prioritize your progress, celebrate your wins, and provide
|
||||
a supportive environment where you can thrive. Check out our openings today.
|
||||
</p>
|
||||
<Link
|
||||
href="#"
|
||||
className="inline-block px-6 py-3 rounded-full bg-[#0e3a24] text-white font-semibold hover:bg-[#0b2d1d] transition"
|
||||
>
|
||||
View open roles
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{/* SECTION 6 */}
|
||||
<section className="bg-[#f7e1d2] py-16">
|
||||
<div className="max-w-6xl px-4 mx-auto md:grid md:grid-cols-2 md:gap-8 md:items-center">
|
||||
{/* Left Side: Text */}
|
||||
<div className="mb-8 md:mb-0">
|
||||
<h2 className="mb-4 text-4xl font-bold text-gray-900">
|
||||
We’re better together. Start building your dream team.
|
||||
</h2>
|
||||
<p className="mb-6 text-gray-700">
|
||||
Design a custom outsourcing solution that drives results.
|
||||
</p>
|
||||
|
||||
{/* ปุ่ม Get Started สีแดง */}
|
||||
<Link
|
||||
href="#"
|
||||
className="inline-flex items-center px-6 py-3 text-lg font-semibold text-white transition bg-red-600 rounded-full hover:bg-red-700"
|
||||
>
|
||||
Get Started
|
||||
<span className="inline-flex items-center justify-center w-8 h-8 ml-2 bg-white rounded-full">
|
||||
{/* ไอคอนลูกศร → */}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#D32F2F">
|
||||
<path d="m600-216-51-51 177-177H96v-72h630L549-693l51-51 264 264-264 264Z"/>
|
||||
</svg>
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Right Side: Image */}
|
||||
<div className="flex justify-center">
|
||||
<Image
|
||||
src="/assets/image8.png"
|
||||
alt="Building Dream Team"
|
||||
width={400}
|
||||
height={300}
|
||||
className="rounded-lg shadow-md"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<footer className="bg-[#bfc1b9] py-8">
|
||||
<div className="max-w-6xl px-4 mx-auto">
|
||||
{/* Top Row: Logo + Middle Columns + Get Started Button */}
|
||||
<div className="flex flex-col md:flex-row md:items-start md:justify-between">
|
||||
{/* Logo (Left) */}
|
||||
<div className="mb-6 md:mb-0">
|
||||
<Image
|
||||
src="/assets/image.png"
|
||||
alt="SupportNinja Logo"
|
||||
width={150}
|
||||
height={40}
|
||||
className="mb-2"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Middle Columns (Solutions, Industries, Resources, Follow, Company) */}
|
||||
<div className="flex flex-wrap gap-8">
|
||||
{/* Column: Solutions */}
|
||||
<div>
|
||||
<h4 className="mb-2 font-bold text-gray-900">Solutions</h4>
|
||||
<ul className="space-y-1 text-sm text-gray-900">
|
||||
<li><Link href="#">Customer Experience</Link></li>
|
||||
<li><Link href="#">Customer Conversion</Link></li>
|
||||
<li><Link href="#">Customer Onboarding</Link></li>
|
||||
<li><Link href="#">Customer Support</Link></li>
|
||||
<li><Link href="#">Technical Customer Support</Link></li>
|
||||
<li><Link href="#">Customer Renewals</Link></li>
|
||||
<li><Link href="#">Content Moderation</Link></li>
|
||||
<li><Link href="#">Data Processing</Link></li>
|
||||
<li><Link href="#">Finance & Accounting</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Column: Industries */}
|
||||
<div>
|
||||
<h4 className="mb-2 font-bold text-gray-900">Industries</h4>
|
||||
<ul className="space-y-1 text-sm text-gray-900">
|
||||
<li><Link href="#">SaaS</Link></li>
|
||||
<li><Link href="#">AI</Link></li>
|
||||
<li><Link href="#">Ecommerce</Link></li>
|
||||
<li><Link href="#">Healthcare</Link></li>
|
||||
<li><Link href="#">Supply Chain & Logistics</Link></li>
|
||||
<li><Link href="#">Fintech</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Column: Resources */}
|
||||
<div>
|
||||
<h4 className="mb-2 font-bold text-gray-900">Resources</h4>
|
||||
<ul className="space-y-1 text-sm text-gray-900">
|
||||
<li><Link href="#">Resources</Link></li>
|
||||
<li><Link href="#">FAQs</Link></li>
|
||||
<li><Link href="#">Glossary</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Column: Follow */}
|
||||
<div>
|
||||
<h4 className="mb-2 font-bold text-gray-900">Follow</h4>
|
||||
<ul className="space-y-1 text-sm text-gray-900">
|
||||
<li><Link href="#">LinkedIn</Link></li>
|
||||
<li><Link href="#">YouTube</Link></li>
|
||||
<li><Link href="#">Twitter</Link></li>
|
||||
<li><Link href="#">Facebook</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Column: Company */}
|
||||
<div>
|
||||
<h4 className="mb-2 font-bold text-gray-900">Company</h4>
|
||||
<ul className="space-y-1 text-sm text-gray-900">
|
||||
<li><Link href="#">How it Works</Link></li>
|
||||
<li><Link href="#">About</Link></li>
|
||||
<li><Link href="#">Careers</Link></li>
|
||||
<li><Link href="#">Contact</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Get Started Button (Right) */}
|
||||
<div className="mt-6 md:mt-0">
|
||||
<Link
|
||||
href="#"
|
||||
className="inline-block px-6 py-3 text-lg font-semibold text-white transition bg-red-600 rounded-full hover:bg-red-700"
|
||||
>
|
||||
Get started
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom Row: Copyright & Policy */}
|
||||
<div className="flex flex-col pt-4 mt-6 text-sm text-gray-700 border-t border-gray-400 md:flex-row md:items-center md:justify-between">
|
||||
<p>© 2025 SupportNinja, a registered trademark of Ninja Partners, LLC</p>
|
||||
<div className="flex mt-2 space-x-4 md:mt-0">
|
||||
<Link href="#" className="hover:underline">
|
||||
Privacy Policy
|
||||
</Link>
|
||||
<Link href="#" className="hover:underline">
|
||||
Security Policy
|
||||
</Link>
|
||||
<Link href="#" className="hover:underline">
|
||||
Terms of Use
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{/* ----------------------------------------------------------------------- */}
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@ const config: NextConfig = {
|
|||
fullUrl: true,
|
||||
},
|
||||
},
|
||||
images: {
|
||||
domains: ["raw.githubusercontent.com"], // ✅ อนุญาตโหลดรูปจาก GitHub
|
||||
unoptimized: true, // ✅ ปิดการ Optimize รูปภาพ (ถ้าต้องการโหลด URL ตรง)
|
||||
},
|
||||
rewrites: async () => [
|
||||
{ source: "/healthz", destination: "/api/health" },
|
||||
{ source: "/api/healthz", destination: "/api/health" },
|
||||
|
|
|
|||
BIN
public/assets/image.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
public/assets/image2.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
public/assets/image3.png
Normal file
|
After Width: | Height: | Size: 169 KiB |
BIN
public/assets/image4.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
public/assets/image5.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
public/assets/image6.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
public/assets/image7.png
Normal file
|
After Width: | Height: | Size: 359 KiB |
BIN
public/assets/image8.png
Normal file
|
After Width: | Height: | Size: 190 KiB |
BIN
public/assets/midjourney.png
Normal file
|
After Width: | Height: | Size: 24 KiB |