Spaces:
Configuration error
Configuration error
Upload 74 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .eslintrc.json +3 -0
- .gitattributes +12 -35
- .gitignore +17 -4
- README.md +32 -63
- next.config.mjs +6 -0
- package-lock.json +0 -0
- package.json +45 -31
- postcss.config.mjs +8 -0
- public/b1.jpg +0 -0
- public/b1.png +3 -0
- public/b1.svg +0 -0
- public/b2.jpg +3 -0
- public/b3.jpg +3 -0
- public/b4.svg +17 -0
- public/b5.jpg +3 -0
- public/b5.png +3 -0
- public/b5.svg +0 -0
- public/grid.svg +0 -0
- public/next.svg +1 -0
- public/partner01.svg +10 -0
- public/partner02.svg +5 -0
- public/partner03.svg +15 -0
- public/partner04.svg +4 -0
- public/sodaimage/bg.png +3 -0
- public/sodaimage/bg03.png +3 -0
- public/sodaimage/bg2.png +0 -0
- public/sodaimage/mockup.png +3 -0
- public/vercel.svg +1 -0
- public/works/works01.jpg +0 -0
- public/works/works02.jpg +3 -0
- public/works/works03.jpg +3 -0
- public/works/works04.jpg +0 -0
- public/works/works05.jpg +0 -0
- src/app/favicon.ico +0 -0
- src/app/globals.css +160 -0
- src/app/layout.tsx +28 -0
- src/app/page.tsx +17 -0
- src/components/About.tsx +52 -0
- src/components/CanvasMenu/Button/index.jsx +36 -0
- src/components/CanvasMenu/Button/style.module.scss +68 -0
- src/components/CanvasMenu/Nav/anim.js +44 -0
- src/components/CanvasMenu/Nav/data.js +37 -0
- src/components/CanvasMenu/Nav/index.jsx +54 -0
- src/components/CanvasMenu/Nav/style.module.scss +64 -0
- src/components/CanvasMenu/index.jsx +44 -0
- src/components/CanvasMenu/style.module.scss +17 -0
- src/components/Footer.tsx +130 -0
- src/components/Header.tsx +22 -0
- src/components/Hero.tsx +25 -0
- src/components/LostOrb/index.jsx +11 -0
.eslintrc.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"extends": "next/core-web-vitals"
|
| 3 |
+
}
|
.gitattributes
CHANGED
|
@@ -1,35 +1,12 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
-
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
-
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
-
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 1 |
+
# Auto detect text files and perform LF normalization
|
| 2 |
+
* text=auto
|
| 3 |
+
public/b1.png filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
public/b2.jpg filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
public/b3.jpg filter=lfs diff=lfs merge=lfs -text
|
| 6 |
+
public/b5.jpg filter=lfs diff=lfs merge=lfs -text
|
| 7 |
+
public/b5.png filter=lfs diff=lfs merge=lfs -text
|
| 8 |
+
public/sodaimage/bg.png filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
public/sodaimage/bg03.png filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
public/sodaimage/mockup.png filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
public/works/works02.jpg filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
public/works/works03.jpg filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.gitignore
CHANGED
|
@@ -4,20 +4,33 @@
|
|
| 4 |
/node_modules
|
| 5 |
/.pnp
|
| 6 |
.pnp.js
|
|
|
|
| 7 |
|
| 8 |
# testing
|
| 9 |
/coverage
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
# production
|
| 12 |
/build
|
| 13 |
|
| 14 |
# misc
|
| 15 |
.DS_Store
|
| 16 |
-
|
| 17 |
-
.env.development.local
|
| 18 |
-
.env.test.local
|
| 19 |
-
.env.production.local
|
| 20 |
|
|
|
|
| 21 |
npm-debug.log*
|
| 22 |
yarn-debug.log*
|
| 23 |
yarn-error.log*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
/node_modules
|
| 5 |
/.pnp
|
| 6 |
.pnp.js
|
| 7 |
+
.yarn/install-state.gz
|
| 8 |
|
| 9 |
# testing
|
| 10 |
/coverage
|
| 11 |
|
| 12 |
+
# next.js
|
| 13 |
+
/.next/
|
| 14 |
+
/out/
|
| 15 |
+
|
| 16 |
# production
|
| 17 |
/build
|
| 18 |
|
| 19 |
# misc
|
| 20 |
.DS_Store
|
| 21 |
+
*.pem
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
+
# debug
|
| 24 |
npm-debug.log*
|
| 25 |
yarn-debug.log*
|
| 26 |
yarn-error.log*
|
| 27 |
+
|
| 28 |
+
# local env files
|
| 29 |
+
.env*.local
|
| 30 |
+
|
| 31 |
+
# vercel
|
| 32 |
+
.vercel
|
| 33 |
+
|
| 34 |
+
# typescript
|
| 35 |
+
*.tsbuildinfo
|
| 36 |
+
next-env.d.ts
|
README.md
CHANGED
|
@@ -1,81 +1,50 @@
|
|
| 1 |
-
|
| 2 |
-
title: Web Agency
|
| 3 |
-
emoji: 🐠
|
| 4 |
-
colorFrom: indigo
|
| 5 |
-
colorTo: red
|
| 6 |
-
sdk: static
|
| 7 |
-
pinned: false
|
| 8 |
-
app_build_command: npm run build
|
| 9 |
-
app_file: build/index.html
|
| 10 |
-
---
|
| 11 |
|
| 12 |
-
|
| 13 |
|
| 14 |
-
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
| 15 |
|
| 16 |
-
##
|
| 17 |
|
| 18 |
-
|
|
|
|
| 19 |
|
| 20 |
-
|
| 21 |
|
| 22 |
-
|
| 23 |
-
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
|
| 24 |
|
| 25 |
-
|
| 26 |
-
|
|
|
|
| 27 |
|
| 28 |
-
|
| 29 |
|
| 30 |
-
|
| 31 |
-
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
| 32 |
|
| 33 |
-
|
| 34 |
|
| 35 |
-
|
| 36 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
|
| 38 |
-
|
| 39 |
-
Your app is ready to be deployed!
|
| 40 |
|
| 41 |
-
|
| 42 |
|
| 43 |
-
|
|
|
|
|
|
|
| 44 |
|
| 45 |
-
|
|
|
|
| 46 |
|
| 47 |
-
|
|
|
|
| 48 |
|
| 49 |
-
|
|
|
|
| 50 |
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
## Learn More
|
| 54 |
-
|
| 55 |
-
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
|
| 56 |
-
|
| 57 |
-
To learn React, check out the [React documentation](https://reactjs.org/).
|
| 58 |
-
|
| 59 |
-
### Code Splitting
|
| 60 |
-
|
| 61 |
-
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
|
| 62 |
-
|
| 63 |
-
### Analyzing the Bundle Size
|
| 64 |
-
|
| 65 |
-
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
|
| 66 |
-
|
| 67 |
-
### Making a Progressive Web App
|
| 68 |
-
|
| 69 |
-
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
|
| 70 |
-
|
| 71 |
-
### Advanced Configuration
|
| 72 |
-
|
| 73 |
-
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
|
| 74 |
-
|
| 75 |
-
### Deployment
|
| 76 |
-
|
| 77 |
-
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
|
| 78 |
-
|
| 79 |
-
### `npm run build` fails to minify
|
| 80 |
-
|
| 81 |
-
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
|
|
|
|
| 1 |
+
# Agency Website
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
+
Welcome to the **Agency Website** project! This is a modern, responsive website template built using **Next.js**. It's designed to showcase agency services with a sleek and interactive design, incorporating 3D elements using **Spline**, and animations with **Framer Motion**. The website is styled with **Tailwind CSS** and developed with **TypeScript** for robust type safety.
|
| 4 |
|
|
|
|
| 5 |
|
| 6 |
+
## 🔗 Live Demo
|
| 7 |
|
| 8 |
+
Check out the live version of the Agency Website:
|
| 9 |
+
[**Live Demo**](https://agency01.vercel.app/)
|
| 10 |
|
| 11 |
+
## 🚀 Purpose
|
| 12 |
|
| 13 |
+
The goal of this project is to provide a visually stunning and interactive website template for agencies. The website features:
|
|
|
|
| 14 |
|
| 15 |
+
- A modern, professional design.
|
| 16 |
+
- 3D elements and animations to enhance user experience.
|
| 17 |
+
- Responsive layout to ensure optimal viewing on all devices.
|
| 18 |
|
| 19 |
+
Built with **Next.js** for server-side rendering and static site generation, **Tailwind CSS** for utility-first styling, **Framer Motion** for animations, **Spline** for 3D graphics, and **TypeScript** for type safety, this template offers both flexibility and performance.
|
| 20 |
|
| 21 |
+
## 🛠️ Frameworks & Technologies
|
|
|
|
| 22 |
|
| 23 |
+
This project utilizes the following technologies:
|
| 24 |
|
| 25 |
+
- **Next.js** - React framework for server-side rendering (SSR) and static site generation (SSG).
|
| 26 |
+
- **React** - For building the user interface with reusable components.
|
| 27 |
+
- **Tailwind CSS** - For utility-first styling and responsive design.
|
| 28 |
+
- **Framer Motion** - For smooth animations and interactive elements.
|
| 29 |
+
- **Spline** - For integrating 3D graphics into the website.
|
| 30 |
+
- **TypeScript** - For static type checking and improved code quality.
|
| 31 |
|
| 32 |
+
## 📝 Setup & Customization
|
|
|
|
| 33 |
|
| 34 |
+
To get started with the project:
|
| 35 |
|
| 36 |
+
```bash
|
| 37 |
+
# Clone the repository
|
| 38 |
+
git clone https://github.com/charltonkdev/agency-website.git
|
| 39 |
|
| 40 |
+
# Navigate to the project folder
|
| 41 |
+
cd agency-website
|
| 42 |
|
| 43 |
+
# Install dependencies
|
| 44 |
+
npm install
|
| 45 |
|
| 46 |
+
# Run the development server
|
| 47 |
+
npm run dev
|
| 48 |
|
| 49 |
+
# Open http://localhost:3000 in your browser to view the project
|
| 50 |
+
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
next.config.mjs
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/** @type {import('next').NextConfig} */
|
| 2 |
+
const nextConfig = {
|
| 3 |
+
};
|
| 4 |
+
|
| 5 |
+
export default nextConfig;
|
| 6 |
+
|
package-lock.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
package.json
CHANGED
|
@@ -1,39 +1,53 @@
|
|
| 1 |
{
|
| 2 |
-
"name": "
|
| 3 |
"version": "0.1.0",
|
| 4 |
"private": true,
|
| 5 |
-
"dependencies": {
|
| 6 |
-
"@testing-library/dom": "^10.4.0",
|
| 7 |
-
"@testing-library/jest-dom": "^6.6.3",
|
| 8 |
-
"@testing-library/react": "^16.3.0",
|
| 9 |
-
"@testing-library/user-event": "^13.5.0",
|
| 10 |
-
"react": "^19.1.0",
|
| 11 |
-
"react-dom": "^19.1.0",
|
| 12 |
-
"react-scripts": "5.0.1",
|
| 13 |
-
"web-vitals": "^2.1.4"
|
| 14 |
-
},
|
| 15 |
"scripts": {
|
| 16 |
-
"
|
| 17 |
-
"build": "
|
| 18 |
-
"
|
| 19 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
},
|
| 21 |
-
"
|
| 22 |
-
"
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
},
|
| 27 |
-
"
|
| 28 |
-
"
|
| 29 |
-
">0.2%",
|
| 30 |
-
"not dead",
|
| 31 |
-
"not op_mini all"
|
| 32 |
-
],
|
| 33 |
-
"development": [
|
| 34 |
-
"last 1 chrome version",
|
| 35 |
-
"last 1 firefox version",
|
| 36 |
-
"last 1 safari version"
|
| 37 |
-
]
|
| 38 |
}
|
| 39 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"name": "agency01",
|
| 3 |
"version": "0.1.0",
|
| 4 |
"private": true,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
"scripts": {
|
| 6 |
+
"dev": "next dev",
|
| 7 |
+
"build": "next build",
|
| 8 |
+
"start": "next start",
|
| 9 |
+
"lint": "next lint"
|
| 10 |
+
},
|
| 11 |
+
"dependencies": {
|
| 12 |
+
"@react-three/drei": "^9.108.3",
|
| 13 |
+
"@react-three/fiber": "^8.16.8",
|
| 14 |
+
"@splinetool/react-spline": "^4.0.0",
|
| 15 |
+
"@splinetool/runtime": "^1.8.9",
|
| 16 |
+
"@studio-freight/lenis": "^1.0.42",
|
| 17 |
+
"@tabler/icons-react": "^3.9.0",
|
| 18 |
+
"@tsparticles/engine": "^3.5.0",
|
| 19 |
+
"@tsparticles/react": "^3.0.0",
|
| 20 |
+
"@tsparticles/slim": "^3.5.0",
|
| 21 |
+
"clsx": "^2.1.1",
|
| 22 |
+
"framer-motion": "^11.2.14",
|
| 23 |
+
"gsap": "^3.12.5",
|
| 24 |
+
"lenis": "^1.1.5",
|
| 25 |
+
"locomotive-scroll": "^4.1.4",
|
| 26 |
+
"mini-svg-data-uri": "^1.4.4",
|
| 27 |
+
"next": "14.2.4",
|
| 28 |
+
"react": "^18.3.1",
|
| 29 |
+
"react-dom": "^18.3.1",
|
| 30 |
+
"react-feather": "^2.0.10",
|
| 31 |
+
"react-icons": "^5.2.1",
|
| 32 |
+
"sass": "^1.77.6",
|
| 33 |
+
"simplex-noise": "^4.0.1",
|
| 34 |
+
"tailwind-merge": "^2.4.0",
|
| 35 |
+
"tailwindcss-animate": "^1.0.7",
|
| 36 |
+
"three": "^0.166.1",
|
| 37 |
+
"three-globe": "^2.31.1"
|
| 38 |
},
|
| 39 |
+
"devDependencies": {
|
| 40 |
+
"@types/locomotive-scroll": "^4.1.3",
|
| 41 |
+
"@types/node": "^20",
|
| 42 |
+
"@types/react": "^18",
|
| 43 |
+
"@types/react-dom": "^18",
|
| 44 |
+
"eslint": "^8",
|
| 45 |
+
"eslint-config-next": "14.2.4",
|
| 46 |
+
"postcss": "^8",
|
| 47 |
+
"tailwindcss": "^3.4.1",
|
| 48 |
+
"typescript": "^5"
|
| 49 |
},
|
| 50 |
+
"overrides": {
|
| 51 |
+
"three": "^0.166.1"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
}
|
| 53 |
}
|
postcss.config.mjs
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/** @type {import('postcss-load-config').Config} */
|
| 2 |
+
const config = {
|
| 3 |
+
plugins: {
|
| 4 |
+
tailwindcss: {},
|
| 5 |
+
},
|
| 6 |
+
};
|
| 7 |
+
|
| 8 |
+
export default config;
|
public/b1.jpg
ADDED
|
public/b1.png
ADDED
|
Git LFS Details
|
public/b1.svg
ADDED
|
|
public/b2.jpg
ADDED
|
Git LFS Details
|
public/b3.jpg
ADDED
|
Git LFS Details
|
public/b4.svg
ADDED
|
|
public/b5.jpg
ADDED
|
Git LFS Details
|
public/b5.png
ADDED
|
Git LFS Details
|
public/b5.svg
ADDED
|
|
public/grid.svg
ADDED
|
|
public/next.svg
ADDED
|
|
public/partner01.svg
ADDED
|
|
public/partner02.svg
ADDED
|
|
public/partner03.svg
ADDED
|
|
public/partner04.svg
ADDED
|
|
public/sodaimage/bg.png
ADDED
|
Git LFS Details
|
public/sodaimage/bg03.png
ADDED
|
Git LFS Details
|
public/sodaimage/bg2.png
ADDED
|
public/sodaimage/mockup.png
ADDED
|
Git LFS Details
|
public/vercel.svg
ADDED
|
|
public/works/works01.jpg
ADDED
|
public/works/works02.jpg
ADDED
|
Git LFS Details
|
public/works/works03.jpg
ADDED
|
Git LFS Details
|
public/works/works04.jpg
ADDED
|
public/works/works05.jpg
ADDED
|
src/app/favicon.ico
ADDED
|
|
src/app/globals.css
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
@tailwind base;
|
| 2 |
+
@tailwind components;
|
| 3 |
+
@tailwind utilities;
|
| 4 |
+
|
| 5 |
+
:root {
|
| 6 |
+
--foreground-rgb: 11, 13, 33;
|
| 7 |
+
--background-start-rgb: 214, 219, 220;
|
| 8 |
+
--background-end-rgb: 0, 0, 0;
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
body {
|
| 13 |
+
color: rgb(var(--background-start-rgb));
|
| 14 |
+
background: rgb(var(--foreground-rgb));
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
@layer utilities {
|
| 18 |
+
.text-balance {
|
| 19 |
+
text-wrap: balance;
|
| 20 |
+
}
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
html.lenis, html.lenis body {
|
| 24 |
+
height: auto;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
.lenis.lenis-smooth {
|
| 28 |
+
scroll-behavior: auto !important;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
.lenis.lenis-smooth [data-lenis-prevent] {
|
| 32 |
+
overscroll-behavior: contain;
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
.lenis.lenis-stopped {
|
| 36 |
+
overflow: hidden;
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
.lenis.lenis-smooth iframe {
|
| 40 |
+
pointer-events: none;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
.creativeBtn{
|
| 44 |
+
transition: 0.3s ease-in-out;
|
| 45 |
+
position: relative;
|
| 46 |
+
overflow: hidden;
|
| 47 |
+
border: 1px solid #fff;
|
| 48 |
+
}
|
| 49 |
+
.creativeBtn:hover {
|
| 50 |
+
color: #fff;
|
| 51 |
+
}
|
| 52 |
+
.creativeBtn span {
|
| 53 |
+
position: relative;
|
| 54 |
+
z-index: 9;
|
| 55 |
+
}
|
| 56 |
+
.creativeBtn:after {
|
| 57 |
+
content: '';
|
| 58 |
+
width: 100px;
|
| 59 |
+
height: 100px;
|
| 60 |
+
border-radius: 100%;
|
| 61 |
+
background:#000;
|
| 62 |
+
position: absolute;
|
| 63 |
+
display: block;
|
| 64 |
+
left: 0;
|
| 65 |
+
top:calc(-5vh);
|
| 66 |
+
z-index: 0;
|
| 67 |
+
scale: 0;
|
| 68 |
+
transition: 0.3s ease-in-out;
|
| 69 |
+
}
|
| 70 |
+
.creativeBtn:hover:after{
|
| 71 |
+
scale: 1.2;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
/* components/Banner.module.css */
|
| 76 |
+
|
| 77 |
+
.product {
|
| 78 |
+
position: absolute;
|
| 79 |
+
right: 0;
|
| 80 |
+
transform: translateX(60%);
|
| 81 |
+
bottom: calc(-10vw);
|
| 82 |
+
z-index: 2;
|
| 83 |
+
width: 500px;
|
| 84 |
+
transition: 0.7s;
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
.product .soda {
|
| 88 |
+
position: absolute;
|
| 89 |
+
bottom: 0;
|
| 90 |
+
right: 50%;
|
| 91 |
+
transform: translateX(-50%);
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
.soda {
|
| 95 |
+
--left: 0px;
|
| 96 |
+
background: var(--url) var(--left), url(/sodaimage/mockup.png) 0 0;
|
| 97 |
+
background-size: auto 100%;
|
| 98 |
+
width: 250px;
|
| 99 |
+
aspect-ratio: 2 / 4;
|
| 100 |
+
background-blend-mode: multiply;
|
| 101 |
+
transition: 0.8s;
|
| 102 |
+
mask-image: url(/sodaimage/mockup.png);
|
| 103 |
+
mask-size: auto 100%;
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
.soda:nth-child(2) {
|
| 107 |
+
opacity: 0;
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
.brandContainer:hover .product {
|
| 111 |
+
bottom: 100px;
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
.brandContainer:hover .product .soda:nth-child(2) {
|
| 115 |
+
opacity: 1;
|
| 116 |
+
--left: 500px;
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
.brandContainer:hover .product .soda:nth-child(1) {
|
| 120 |
+
opacity: 0;
|
| 121 |
+
--left: 500px;
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
@media screen and (max-width: 1023px) {
|
| 125 |
+
.soda {
|
| 126 |
+
width: 250px;
|
| 127 |
+
}
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
@media screen and (max-width: 767px) {
|
| 131 |
+
.soda {
|
| 132 |
+
width: 150px;
|
| 133 |
+
}
|
| 134 |
+
.product {
|
| 135 |
+
bottom: -260px;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
.brandContainer:hover .product {
|
| 139 |
+
bottom: -150px;
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
.brandContainer:hover .product .soda:nth-child(2) {
|
| 143 |
+
--left: 300px;
|
| 144 |
+
}
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
@keyframes slideFadeInUp {
|
| 148 |
+
from {
|
| 149 |
+
opacity: 0;
|
| 150 |
+
transform: translateY(30px);
|
| 151 |
+
}
|
| 152 |
+
to {
|
| 153 |
+
opacity: 1;
|
| 154 |
+
transform: translateY(0);
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
.orbStyle {
|
| 159 |
+
animation: slideFadeInUp 1s ease forwards;
|
| 160 |
+
}
|
src/app/layout.tsx
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import type { Metadata } from "next";
|
| 2 |
+
import { Inter } from "next/font/google";
|
| 3 |
+
import "./globals.css";
|
| 4 |
+
import Menu from "@/components/Menu";
|
| 5 |
+
import Footer from "@/components/Footer";
|
| 6 |
+
|
| 7 |
+
const inter = Inter({ subsets: ["latin"] });
|
| 8 |
+
|
| 9 |
+
export const metadata: Metadata = {
|
| 10 |
+
title: "Website Agency",
|
| 11 |
+
description: "We build your ideas",
|
| 12 |
+
};
|
| 13 |
+
|
| 14 |
+
export default function RootLayout({
|
| 15 |
+
children,
|
| 16 |
+
}: Readonly<{
|
| 17 |
+
children: React.ReactNode;
|
| 18 |
+
}>) {
|
| 19 |
+
return (
|
| 20 |
+
<html lang="en">
|
| 21 |
+
<body className={`${inter.className} overflow-x-hidden relative`} >
|
| 22 |
+
<Menu />
|
| 23 |
+
{children}
|
| 24 |
+
<Footer />
|
| 25 |
+
</body>
|
| 26 |
+
</html>
|
| 27 |
+
);
|
| 28 |
+
}
|
src/app/page.tsx
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import About from "@/components/About";
|
| 2 |
+
import Hero from "@/components/Hero";
|
| 3 |
+
import Services from '@/components/Services';
|
| 4 |
+
import LenisScroll from '@/components/ui/LenisScroll';
|
| 5 |
+
import Works from "@/components/Works";
|
| 6 |
+
|
| 7 |
+
export default function Home() {
|
| 8 |
+
return (
|
| 9 |
+
<main className='flex relative min-h-screen flex-col items-center justify-between overflow-x-hidden'>
|
| 10 |
+
<LenisScroll />
|
| 11 |
+
<Hero />
|
| 12 |
+
<About />
|
| 13 |
+
<Services />
|
| 14 |
+
<Works />
|
| 15 |
+
</main>
|
| 16 |
+
);
|
| 17 |
+
}
|
src/components/About.tsx
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
import React, { useRef, useEffect, useState } from 'react';
|
| 3 |
+
import { motion } from "framer-motion";
|
| 4 |
+
|
| 5 |
+
const About = () => {
|
| 6 |
+
const [isVisible, setIsVisible] = useState(false);
|
| 7 |
+
const [hasAnimated, setHasAnimated] = useState(false);
|
| 8 |
+
const ref = useRef<HTMLDivElement>(null);
|
| 9 |
+
|
| 10 |
+
useEffect(() => {
|
| 11 |
+
const observer = new IntersectionObserver(
|
| 12 |
+
([entry]) => {
|
| 13 |
+
if (entry.isIntersecting && !hasAnimated) {
|
| 14 |
+
setIsVisible(true);
|
| 15 |
+
setHasAnimated(true); // Ensure the animation plays only once
|
| 16 |
+
} else if (!entry.isIntersecting && entry.boundingClientRect.top > 0) {
|
| 17 |
+
setIsVisible(false);
|
| 18 |
+
setHasAnimated(false); // Reset the animation when scrolling up
|
| 19 |
+
}
|
| 20 |
+
},
|
| 21 |
+
{
|
| 22 |
+
threshold: 0.5, // Adjust threshold as needed
|
| 23 |
+
}
|
| 24 |
+
);
|
| 25 |
+
|
| 26 |
+
if (ref.current) {
|
| 27 |
+
observer.observe(ref.current);
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
return () => {
|
| 31 |
+
if (ref.current) {
|
| 32 |
+
observer.unobserve(ref.current);
|
| 33 |
+
}
|
| 34 |
+
};
|
| 35 |
+
}, [hasAnimated]);
|
| 36 |
+
|
| 37 |
+
return (
|
| 38 |
+
<div className='relative flex flex-col w-full h-screen p-12 lg:p-24 justify-center items-center bg-black z-10'>
|
| 39 |
+
<motion.div
|
| 40 |
+
ref={ref}
|
| 41 |
+
initial={{ opacity: 0, y: 50 }}
|
| 42 |
+
animate={isVisible ? { opacity: 1, y: 0 } : { opacity: 0, y: 50 }}
|
| 43 |
+
transition={{ duration: 0.5 }}
|
| 44 |
+
className='flex z-50 flex-col w-full text-xl leading-[2] md:text-3xl max-w-4xl md:leading-[2]'
|
| 45 |
+
>
|
| 46 |
+
Welcome to iDEA agency, where creativity meets technology. We are a team of passionate designers and developers dedicated to crafting stunning websites that not only look great but also deliver exceptional user experiences. With years of industry experience, we specialize in creating custom digital solutions tailored to your business needs. Our mission is to elevate your brand online and help you stand out in the digital landscape.
|
| 47 |
+
</motion.div>
|
| 48 |
+
</div>
|
| 49 |
+
);
|
| 50 |
+
};
|
| 51 |
+
|
| 52 |
+
export default About;
|
src/components/CanvasMenu/Button/index.jsx
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { motion } from 'framer-motion';
|
| 2 |
+
import styles from './style.module.scss';
|
| 3 |
+
|
| 4 |
+
export default function Button({isActive, toggleMenu}) {
|
| 5 |
+
return (
|
| 6 |
+
<div className={styles.button}>
|
| 7 |
+
<motion.div
|
| 8 |
+
className={styles.slider}
|
| 9 |
+
animate={{top: isActive ? "-100%" : "0%"}}
|
| 10 |
+
transition={{ duration: 0.5, type: "tween", ease: [0.76, 0, 0.24, 1]}}
|
| 11 |
+
>
|
| 12 |
+
<div
|
| 13 |
+
className={styles.el}
|
| 14 |
+
onClick={() => {toggleMenu()}}
|
| 15 |
+
>
|
| 16 |
+
<PerspectiveText label="Menu"/>
|
| 17 |
+
</div>
|
| 18 |
+
<div
|
| 19 |
+
className={styles.el}
|
| 20 |
+
onClick={() => {toggleMenu()}}
|
| 21 |
+
>
|
| 22 |
+
<PerspectiveText label="Close" />
|
| 23 |
+
</div>
|
| 24 |
+
</motion.div>
|
| 25 |
+
</div>
|
| 26 |
+
)
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
function PerspectiveText({label}) {
|
| 30 |
+
return (
|
| 31 |
+
<div className={styles.perspectiveText}>
|
| 32 |
+
<p>{label}</p>
|
| 33 |
+
<p>{label}</p>
|
| 34 |
+
</div>
|
| 35 |
+
)
|
| 36 |
+
}
|
src/components/CanvasMenu/Button/style.module.scss
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.button{
|
| 2 |
+
position: absolute;
|
| 3 |
+
top: 0;
|
| 4 |
+
right: 0;
|
| 5 |
+
width: 100px;
|
| 6 |
+
height: 40px;
|
| 7 |
+
cursor: pointer;
|
| 8 |
+
border-radius: 25px;
|
| 9 |
+
overflow: hidden;
|
| 10 |
+
|
| 11 |
+
.slider{
|
| 12 |
+
position: relative;
|
| 13 |
+
width: 100%;
|
| 14 |
+
height: 100%;
|
| 15 |
+
|
| 16 |
+
.el{
|
| 17 |
+
width: 100%;
|
| 18 |
+
height: 100%;
|
| 19 |
+
background-color: #D35A0A;
|
| 20 |
+
p{
|
| 21 |
+
margin: 0px;
|
| 22 |
+
}
|
| 23 |
+
&:nth-of-type(2){
|
| 24 |
+
background-color: #000;
|
| 25 |
+
p{
|
| 26 |
+
color: #fff;
|
| 27 |
+
}
|
| 28 |
+
}
|
| 29 |
+
&:hover{
|
| 30 |
+
.perspectiveText{
|
| 31 |
+
transform: rotateX(90deg);
|
| 32 |
+
p{
|
| 33 |
+
&:nth-of-type(1){
|
| 34 |
+
transform: translateY(-100%);
|
| 35 |
+
opacity: 0;
|
| 36 |
+
}
|
| 37 |
+
&:nth-of-type(2){
|
| 38 |
+
opacity: 1;
|
| 39 |
+
}
|
| 40 |
+
}
|
| 41 |
+
}
|
| 42 |
+
}
|
| 43 |
+
}
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
.perspectiveText{
|
| 49 |
+
display: flex;
|
| 50 |
+
flex-direction: column;
|
| 51 |
+
justify-content: center;
|
| 52 |
+
align-items: center;
|
| 53 |
+
height: 100%;
|
| 54 |
+
width: 100%;
|
| 55 |
+
transform-style: preserve-3d;
|
| 56 |
+
transition: transform 0.5s cubic-bezier(0.6, 0, 0.24, 1);
|
| 57 |
+
p{
|
| 58 |
+
transition: all 0.5s cubic-bezier(0.6, 0, 0.24, 1);
|
| 59 |
+
pointer-events: none;
|
| 60 |
+
text-transform: uppercase;
|
| 61 |
+
&:nth-of-type(2){
|
| 62 |
+
position: absolute;
|
| 63 |
+
transform-origin: bottom center;
|
| 64 |
+
transform: rotateX(-90deg) translateY(9px);
|
| 65 |
+
opacity: 0;
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
}
|
src/components/CanvasMenu/Nav/anim.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export const perspective = {
|
| 2 |
+
initial: {
|
| 3 |
+
opacity: 0,
|
| 4 |
+
rotateX: 90,
|
| 5 |
+
translateY: 80,
|
| 6 |
+
translateX: -20,
|
| 7 |
+
},
|
| 8 |
+
enter: (i) => ({
|
| 9 |
+
opacity: 1,
|
| 10 |
+
rotateX: 0,
|
| 11 |
+
translateY: 0,
|
| 12 |
+
translateX: 0,
|
| 13 |
+
transition: {
|
| 14 |
+
duration: 0.65,
|
| 15 |
+
delay: 0.5 + (i * 0.1),
|
| 16 |
+
ease: [.215,.61,.355,1],
|
| 17 |
+
opacity: { duration: 0.35}
|
| 18 |
+
}
|
| 19 |
+
}),
|
| 20 |
+
exit: {
|
| 21 |
+
opacity: 0,
|
| 22 |
+
transition: { duration: 0.5, type: "linear", ease: [0.76, 0, 0.24, 1]}
|
| 23 |
+
}
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
export const slideIn = {
|
| 27 |
+
initial: {
|
| 28 |
+
opacity: 0,
|
| 29 |
+
y: 20
|
| 30 |
+
},
|
| 31 |
+
enter: (i) => ({
|
| 32 |
+
opacity: 1,
|
| 33 |
+
y: 0,
|
| 34 |
+
transition: {
|
| 35 |
+
duration: 0.5,
|
| 36 |
+
delay: 0.75 + (i * 0.1),
|
| 37 |
+
ease: [.215,.61,.355,1]
|
| 38 |
+
}
|
| 39 |
+
}),
|
| 40 |
+
exit: {
|
| 41 |
+
opacity: 0,
|
| 42 |
+
transition: { duration: 0.5, type: "tween", ease: "easeInOut"}
|
| 43 |
+
}
|
| 44 |
+
}
|
src/components/CanvasMenu/Nav/data.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export const links = [
|
| 2 |
+
{
|
| 3 |
+
title: "About",
|
| 4 |
+
href: "/"
|
| 5 |
+
},
|
| 6 |
+
{
|
| 7 |
+
title: "Works",
|
| 8 |
+
href: "/"
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
title: "Services",
|
| 12 |
+
href: "/"
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
title: "Contact",
|
| 16 |
+
href: "/"
|
| 17 |
+
}
|
| 18 |
+
]
|
| 19 |
+
|
| 20 |
+
export const footerLinks = [
|
| 21 |
+
{
|
| 22 |
+
title: "Facebook",
|
| 23 |
+
href: "/"
|
| 24 |
+
},
|
| 25 |
+
{
|
| 26 |
+
title: "LinkedIn",
|
| 27 |
+
href: "/"
|
| 28 |
+
},
|
| 29 |
+
{
|
| 30 |
+
title: "Instagram",
|
| 31 |
+
href: "/"
|
| 32 |
+
},
|
| 33 |
+
{
|
| 34 |
+
title: "Twitter",
|
| 35 |
+
href: "/"
|
| 36 |
+
}
|
| 37 |
+
]
|
src/components/CanvasMenu/Nav/index.jsx
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import styles from "./style.module.scss";
|
| 2 |
+
import { motion } from "framer-motion";
|
| 3 |
+
import { links, footerLinks } from "./data";
|
| 4 |
+
import Image from "next/image";
|
| 5 |
+
import { perspective, slideIn } from "./anim";
|
| 6 |
+
import clsx from "clsx";
|
| 7 |
+
|
| 8 |
+
export default function index() {
|
| 9 |
+
return (
|
| 10 |
+
<div className={styles.mainNav}>
|
| 11 |
+
<div className={styles.nav}>
|
| 12 |
+
<div className={clsx(styles.body)}>
|
| 13 |
+
{links.map((link, i) => {
|
| 14 |
+
const { title, href } = link;
|
| 15 |
+
return (
|
| 16 |
+
<div key={`b_${i}`} className={styles.linkContainer}>
|
| 17 |
+
<motion.div
|
| 18 |
+
href={href}
|
| 19 |
+
custom={i}
|
| 20 |
+
variants={slideIn}
|
| 21 |
+
initial="initial"
|
| 22 |
+
animate="enter"
|
| 23 |
+
exit="exit"
|
| 24 |
+
>
|
| 25 |
+
<a>{title}</a>
|
| 26 |
+
</motion.div>
|
| 27 |
+
</div>
|
| 28 |
+
);
|
| 29 |
+
})}
|
| 30 |
+
</div>
|
| 31 |
+
<motion.div className={styles.footer}>
|
| 32 |
+
{footerLinks.map((link, i) => {
|
| 33 |
+
const { title, href } = link;
|
| 34 |
+
return (
|
| 35 |
+
<motion.a
|
| 36 |
+
variants={slideIn}
|
| 37 |
+
custom={i}
|
| 38 |
+
initial="initial"
|
| 39 |
+
animate="enter"
|
| 40 |
+
exit="exit"
|
| 41 |
+
key={`f_${i}`}
|
| 42 |
+
>
|
| 43 |
+
{title}
|
| 44 |
+
</motion.a>
|
| 45 |
+
);
|
| 46 |
+
})}
|
| 47 |
+
</motion.div>
|
| 48 |
+
</div>
|
| 49 |
+
<div className="relative block w-[100vw] h-[50vh] pt-[100px]">
|
| 50 |
+
<Image alt src="/b5.jpg" objectFit="cover" width={1280} height={1080}/>
|
| 51 |
+
</div>
|
| 52 |
+
</div>
|
| 53 |
+
);
|
| 54 |
+
}
|
src/components/CanvasMenu/Nav/style.module.scss
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.nav{
|
| 2 |
+
display: flex;
|
| 3 |
+
flex-direction: column;
|
| 4 |
+
justify-content: space-between;
|
| 5 |
+
padding: 100px 40px 50px 40px;
|
| 6 |
+
height: 75vh;
|
| 7 |
+
box-sizing: border-box;
|
| 8 |
+
position: relative;
|
| 9 |
+
.body{
|
| 10 |
+
display: flex;
|
| 11 |
+
gap: 10px;
|
| 12 |
+
flex-direction: column;
|
| 13 |
+
.linkContainer{
|
| 14 |
+
perspective: 120px;
|
| 15 |
+
perspective-origin: bottom;
|
| 16 |
+
}
|
| 17 |
+
a{
|
| 18 |
+
text-decoration: none;
|
| 19 |
+
color: #000;
|
| 20 |
+
font-size: 46px;
|
| 21 |
+
width: max-content;
|
| 22 |
+
display: block;
|
| 23 |
+
transition: 0.2s ease-in-out;
|
| 24 |
+
overflow: hidden;
|
| 25 |
+
cursor: pointer;
|
| 26 |
+
}
|
| 27 |
+
a:after {
|
| 28 |
+
content: '';
|
| 29 |
+
display: block;
|
| 30 |
+
position: relative;
|
| 31 |
+
width: 100%;
|
| 32 |
+
height: 3px;
|
| 33 |
+
background: #000;
|
| 34 |
+
transform: translateX(-100%);
|
| 35 |
+
transition: .3s ease-in-out;
|
| 36 |
+
}
|
| 37 |
+
a:hover:after {
|
| 38 |
+
transform: translateX(0);
|
| 39 |
+
transition: .3s ease-in-out;
|
| 40 |
+
}
|
| 41 |
+
}
|
| 42 |
+
.footer{
|
| 43 |
+
display: flex;
|
| 44 |
+
flex-wrap: wrap;
|
| 45 |
+
a{
|
| 46 |
+
width: 50%;
|
| 47 |
+
margin-top: 5px;
|
| 48 |
+
}
|
| 49 |
+
}
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
.mainNav {
|
| 53 |
+
display: grid;
|
| 54 |
+
position: relative;
|
| 55 |
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
@media (max-width: 1024px){
|
| 59 |
+
.mainNav {
|
| 60 |
+
display: flex !important;
|
| 61 |
+
flex-direction: column !important;
|
| 62 |
+
|
| 63 |
+
}
|
| 64 |
+
}
|
src/components/CanvasMenu/index.jsx
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client';
|
| 2 |
+
import { useState } from 'react'
|
| 3 |
+
import { AnimatePresence, motion } from 'framer-motion';
|
| 4 |
+
import Button from './Button';
|
| 5 |
+
import styles from './style.module.scss';
|
| 6 |
+
import Nav from './Nav';
|
| 7 |
+
import clsx from 'clsx';
|
| 8 |
+
|
| 9 |
+
const menu = {
|
| 10 |
+
open: {
|
| 11 |
+
width: "88vw",
|
| 12 |
+
height: "75vh",
|
| 13 |
+
top: "-25px",
|
| 14 |
+
right: "-25px",
|
| 15 |
+
transition: { duration: 0.5, type: "tween", ease: [0.76, 0, 0.24, 1] }
|
| 16 |
+
},
|
| 17 |
+
closed: {
|
| 18 |
+
width: "100px",
|
| 19 |
+
height: "40px",
|
| 20 |
+
top: "0px",
|
| 21 |
+
right: "0px",
|
| 22 |
+
transition: { duration: 0.5, delay: 0.35, type: "tween", ease: [0.76, 0, 0.24, 1] }
|
| 23 |
+
}
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
export default function Index() {
|
| 27 |
+
const [isActive, setIsActive] = useState(false);
|
| 28 |
+
|
| 29 |
+
return (
|
| 30 |
+
<div className={styles.header}>
|
| 31 |
+
<motion.div
|
| 32 |
+
className={clsx(styles.menu)}
|
| 33 |
+
variants={menu}
|
| 34 |
+
animate={isActive ? "open" : "closed"}
|
| 35 |
+
initial="closed"
|
| 36 |
+
>
|
| 37 |
+
<AnimatePresence>
|
| 38 |
+
{isActive && <Nav />}
|
| 39 |
+
</AnimatePresence>
|
| 40 |
+
</motion.div>
|
| 41 |
+
<Button isActive={isActive} toggleMenu={() => { setIsActive(!isActive) }} />
|
| 42 |
+
</div>
|
| 43 |
+
)
|
| 44 |
+
}
|
src/components/CanvasMenu/style.module.scss
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.header {
|
| 2 |
+
position: fixed;
|
| 3 |
+
right: 50px;
|
| 4 |
+
top: 50px;
|
| 5 |
+
z-index: 99;
|
| 6 |
+
.menu {
|
| 7 |
+
width: 480px;
|
| 8 |
+
height: 650px;
|
| 9 |
+
background-color: #fff;
|
| 10 |
+
border-radius: 25px;
|
| 11 |
+
overflow: hidden;
|
| 12 |
+
position: relative;
|
| 13 |
+
a {
|
| 14 |
+
color: #000;
|
| 15 |
+
}
|
| 16 |
+
}
|
| 17 |
+
}
|
src/components/Footer.tsx
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
import { useRef, useEffect } from 'react';
|
| 3 |
+
import { gsap } from 'gsap';
|
| 4 |
+
|
| 5 |
+
export function Footer() {
|
| 6 |
+
const listItemsRef = useRef<(HTMLLIElement | null)[]>([]);
|
| 7 |
+
const spanItemsRef = useRef<(HTMLSpanElement | null)[]>([]);
|
| 8 |
+
|
| 9 |
+
useEffect(() => {
|
| 10 |
+
const handleMouseEnter = (item: HTMLElement) => {
|
| 11 |
+
const textInitial = item.querySelector('.initial');
|
| 12 |
+
const textHover = item.querySelector('.hover');
|
| 13 |
+
gsap.to(textInitial, {
|
| 14 |
+
yPercent: -100,
|
| 15 |
+
perspective: 1000,
|
| 16 |
+
rotationX: 90,
|
| 17 |
+
duration: 1,
|
| 18 |
+
ease: 'power4.out',
|
| 19 |
+
});
|
| 20 |
+
gsap.to(textHover, {
|
| 21 |
+
yPercent: 0,
|
| 22 |
+
perspective: 1000,
|
| 23 |
+
rotationX: 0,
|
| 24 |
+
duration: 1,
|
| 25 |
+
ease: 'power4.out',
|
| 26 |
+
});
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
const handleMouseLeave = (item: HTMLElement) => {
|
| 30 |
+
const textInitial = item.querySelector('.initial');
|
| 31 |
+
const textHover = item.querySelector('.hover');
|
| 32 |
+
gsap.to(textInitial, {
|
| 33 |
+
yPercent: 0,
|
| 34 |
+
perspective: 1000,
|
| 35 |
+
rotationX: 0,
|
| 36 |
+
duration: 1,
|
| 37 |
+
ease: 'power4.out',
|
| 38 |
+
});
|
| 39 |
+
gsap.to(textHover, {
|
| 40 |
+
yPercent: 100,
|
| 41 |
+
perspective: 1000,
|
| 42 |
+
rotationX: -90,
|
| 43 |
+
duration: 1,
|
| 44 |
+
ease: 'power4.out',
|
| 45 |
+
});
|
| 46 |
+
};
|
| 47 |
+
|
| 48 |
+
const addEventListeners = (item: HTMLElement | null) => {
|
| 49 |
+
if (!item) return;
|
| 50 |
+
const textHover = item.querySelector('.hover');
|
| 51 |
+
gsap.set(textHover, { yPercent: 100, perspective: 1000, rotationX: -90 });
|
| 52 |
+
|
| 53 |
+
const enterHandler = () => handleMouseEnter(item);
|
| 54 |
+
const leaveHandler = () => handleMouseLeave(item);
|
| 55 |
+
|
| 56 |
+
item.addEventListener('mouseenter', enterHandler);
|
| 57 |
+
item.addEventListener('mouseleave', leaveHandler);
|
| 58 |
+
|
| 59 |
+
// Store handlers to remove them later
|
| 60 |
+
(item as any).__enterHandler = enterHandler;
|
| 61 |
+
(item as any).__leaveHandler = leaveHandler;
|
| 62 |
+
};
|
| 63 |
+
|
| 64 |
+
const removeEventListeners = (item: HTMLElement | null) => {
|
| 65 |
+
if (!item) return;
|
| 66 |
+
item.removeEventListener('mouseenter', (item as any).__enterHandler);
|
| 67 |
+
item.removeEventListener('mouseleave', (item as any).__leaveHandler);
|
| 68 |
+
};
|
| 69 |
+
|
| 70 |
+
listItemsRef.current.forEach(addEventListeners);
|
| 71 |
+
spanItemsRef.current.forEach(addEventListeners);
|
| 72 |
+
|
| 73 |
+
return () => {
|
| 74 |
+
listItemsRef.current.forEach(removeEventListeners);
|
| 75 |
+
spanItemsRef.current.forEach(removeEventListeners);
|
| 76 |
+
};
|
| 77 |
+
}, []);
|
| 78 |
+
|
| 79 |
+
return (
|
| 80 |
+
<footer className="flex relative flex-col container py-12 h-screen justify-evenly">
|
| 81 |
+
<div className='flex flex-col'>
|
| 82 |
+
<ul className="flex flex-col gap-5 uppercase w-24">
|
| 83 |
+
{['About', 'Services', 'Works', 'Contact'].map((text, index) => (
|
| 84 |
+
<li
|
| 85 |
+
key={index}
|
| 86 |
+
ref={(el) => { listItemsRef.current[index] = el; }}
|
| 87 |
+
className="relative overflow-hidden h-5 cursor-pointer"
|
| 88 |
+
>
|
| 89 |
+
<span className="block initial absolute top-0 left-0 w-full h-full">{text}</span>
|
| 90 |
+
<span className="block hover absolute top-0 left-0 w-full h-full">{text}</span>
|
| 91 |
+
</li>
|
| 92 |
+
))}
|
| 93 |
+
</ul>
|
| 94 |
+
</div>
|
| 95 |
+
<div className='relative overflow-hidden group/line py-12 mx-auto w-fit cursor-pointer'>
|
| 96 |
+
<h1 className='w-full text-[12vw] uppercase leading-none'>Let's Talk</h1>
|
| 97 |
+
<span className='block w-full bg-white h-3 -translate-x-full group-hover/line:translate-x-0 duration-500 opacity-0 group-hover/line:opacity-100' />
|
| 98 |
+
</div>
|
| 99 |
+
<div className='w-full flex flex-col md:flex-row gap-10 justify-between'>
|
| 100 |
+
<div className='flex gap-10 uppercase'>
|
| 101 |
+
<div className=' relative overflow-hidden group/line cursor-pointer'>
|
| 102 |
+
<h1 className='leading-none pb-2'>mail</h1>
|
| 103 |
+
<span className='block bg-white h-[2px] -translate-x-full group-hover/line:translate-x-0 group-hover/line:opacity-100 opacity-0 duration-500' />
|
| 104 |
+
</div>
|
| 105 |
+
<div className=' relative overflow-hidden group/line cursor-pointer'>
|
| 106 |
+
<h1 className='leading-none pb-2'>github</h1>
|
| 107 |
+
<span className='block bg-white h-[2px] -translate-x-full group-hover/line:translate-x-0 group-hover/line:opacity-100 opacity-0 duration-500' />
|
| 108 |
+
</div>
|
| 109 |
+
<div className=' relative overflow-hidden group/line cursor-pointer'>
|
| 110 |
+
<h1 className='leading-none pb-2'>behance</h1>
|
| 111 |
+
<span className='block bg-white h-[2px] -translate-x-full group-hover/line:translate-x-0 group-hover/line:opacity-100 opacity-0 duration-500' />
|
| 112 |
+
</div>
|
| 113 |
+
<div className=' relative overflow-hidden group/line cursor-pointer'>
|
| 114 |
+
<h1 className='leading-none pb-2'>dribble</h1>
|
| 115 |
+
<span className='block bg-white h-[2px] -translate-x-full group-hover/line:translate-x-0 group-hover/line:opacity-100 opacity-0 duration-500' />
|
| 116 |
+
</div>
|
| 117 |
+
<div className=' relative overflow-hidden group/line cursor-pointer'>
|
| 118 |
+
<h1 className='leading-none pb-2'>linkedin</h1>
|
| 119 |
+
<span className='block bg-white h-[2px] -translate-x-full group-hover/line:translate-x-0 group-hover/line:opacity-100 opacity-0 duration-500' />
|
| 120 |
+
</div>
|
| 121 |
+
</div>
|
| 122 |
+
<div className='flex gap-10 uppercase'>
|
| 123 |
+
<span>2024 © CharltonK.dev</span>
|
| 124 |
+
</div>
|
| 125 |
+
</div>
|
| 126 |
+
</footer>
|
| 127 |
+
);
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
export default Footer;
|
src/components/Header.tsx
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import React from 'react'
|
| 2 |
+
const Header = () => {
|
| 3 |
+
return (
|
| 4 |
+
<header className='w-full flex items-center relative justify-between'>
|
| 5 |
+
<div className='flex'>
|
| 6 |
+
<span className='text-2xl font-bold'>DNA</span>
|
| 7 |
+
</div>
|
| 8 |
+
<div className='flex items-center gap-10'>
|
| 9 |
+
<ul className='flex gap-10 text-gray-400'>
|
| 10 |
+
<li>Home</li>
|
| 11 |
+
<li>Service</li>
|
| 12 |
+
<li>Project</li>
|
| 13 |
+
<li>Contact</li>
|
| 14 |
+
</ul>
|
| 15 |
+
<span className='text-xl font-semibold'>Let's Talk</span>
|
| 16 |
+
</div>
|
| 17 |
+
|
| 18 |
+
</header>
|
| 19 |
+
)
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
export default Header
|
src/components/Hero.tsx
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import React from "react";
|
| 2 |
+
import { Spotlight } from "./ui/Spotlight";
|
| 3 |
+
import HeroContent from "./ui/HeroContent";
|
| 4 |
+
import LostOrb from "./ui/LostOrb";
|
| 5 |
+
|
| 6 |
+
export default function Hero() {
|
| 7 |
+
return (
|
| 8 |
+
<div className="flex flex-col h-screen w-full relative items-center justify-center bg-black bg-grid-white/[0.1]">
|
| 9 |
+
<div className="absolute pointer-events-none inset-0 flex items-center justify-center bg-black [mask-image:radial-gradient(ellipse_at_center,transparent_20%,black)]"></div>
|
| 10 |
+
<Spotlight
|
| 11 |
+
className="-top-40 left-0 md:left-60 md:-top-20"
|
| 12 |
+
fill="orange"
|
| 13 |
+
/>
|
| 14 |
+
<Spotlight
|
| 15 |
+
className="-top-40 left-20 md:left-80 md:-top-20"
|
| 16 |
+
fill="blue"
|
| 17 |
+
/>
|
| 18 |
+
|
| 19 |
+
<HeroContent />
|
| 20 |
+
<div className="w-full h-full absolute bottom-0">
|
| 21 |
+
<LostOrb />
|
| 22 |
+
</div>
|
| 23 |
+
</div>
|
| 24 |
+
);
|
| 25 |
+
}
|
src/components/LostOrb/index.jsx
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import Spline from '@splinetool/react-spline/next';
|
| 2 |
+
|
| 3 |
+
export default function Home() {
|
| 4 |
+
return (
|
| 5 |
+
<main>
|
| 6 |
+
<Spline
|
| 7 |
+
scene="https://prod.spline.design/kVbOOfwISRC36KJd/scene.splinecode"
|
| 8 |
+
/>
|
| 9 |
+
</main>
|
| 10 |
+
);
|
| 11 |
+
}
|