├── .eslintrc.json ├── .github └── workflows │ └── nextjs.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.json ├── .vscode ├── settings.json └── tailwind.json ├── README.md ├── Screenshot.png ├── next.config.mjs ├── package-lock.json ├── package.json ├── postcss.config.mjs ├── public ├── assets │ └── lottie │ │ ├── click.lottie │ │ ├── stars.lottie │ │ └── vroom.lottie ├── next.svg └── vercel.svg ├── src ├── app │ ├── favicon.ico │ ├── layout.tsx │ └── page.tsx ├── assets │ ├── avatar-1.png │ ├── avatar-2.png │ ├── avatar-3.png │ ├── avatar-4.png │ ├── grid-lines.png │ ├── icon-click.svg │ ├── icon-guage.svg │ ├── icon-menu.svg │ ├── icon-stars.svg │ ├── index.ts │ ├── logo-acme.png │ ├── logo-apex.png │ ├── logo-celestial.png │ ├── logo-echo.png │ ├── logo-pulse.png │ ├── logo-quantum.png │ ├── logo.svg │ ├── product-image.png │ ├── social-instagram.svg │ ├── social-x.svg │ ├── social-youtube.svg │ └── stars.png ├── components │ ├── .gitkeep │ ├── Button.tsx │ └── FeatureTab.tsx ├── data │ └── data.ts ├── hooks │ └── useRelativeMousePosition.ts ├── sections │ ├── CallToAction.tsx │ ├── Features.tsx │ ├── Footer.tsx │ ├── Header.tsx │ ├── Hero.tsx │ ├── LogoTicker.tsx │ └── Testimonials.tsx └── styles │ └── globals.css ├── tailwind.config.ts ├── tsconfig.json └── yarn.lock /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": ["next/core-web-vitals", "eslint:recommended"], 4 | "overrides": [ 5 | { 6 | "files": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"] 7 | } 8 | ], 9 | "rules": { 10 | "no-unused-vars": "warn", 11 | "no-console": "warn", 12 | "no-debugger": "error", 13 | "no-alert": "error", 14 | "no-eval": "error", 15 | "no-empty": "error", 16 | "no-undef": "warn", 17 | "no-var": "error", 18 | "eqeqeq": ["error", "always"], 19 | "curly": "error", 20 | "strict": ["error", "global"] 21 | }, 22 | "parserOptions": { 23 | "ecmaVersion": 2020, 24 | "sourceType": "module" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/nextjs.yml: -------------------------------------------------------------------------------- 1 | # Sample workflow for building and deploying a Next.js site to GitHub Pages 2 | # 3 | # To get started with Next.js see: https://nextjs.org/docs/getting-started 4 | # 5 | name: Deploy Next.js site to Pages 6 | 7 | on: 8 | # Runs on pushes targeting the default branch 9 | push: 10 | branches: ["main"] 11 | 12 | # Allows you to run this workflow manually from the Actions tab 13 | workflow_dispatch: 14 | 15 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 16 | permissions: 17 | contents: read 18 | pages: write 19 | id-token: write 20 | 21 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 22 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 23 | concurrency: 24 | group: "pages" 25 | cancel-in-progress: false 26 | 27 | jobs: 28 | # Build job 29 | build: 30 | runs-on: ubuntu-latest 31 | steps: 32 | - name: Checkout 33 | uses: actions/checkout@v4 34 | - name: Detect package manager 35 | id: detect-package-manager 36 | run: | 37 | if [ -f "${{ github.workspace }}/yarn.lock" ]; then 38 | echo "manager=yarn" >> $GITHUB_OUTPUT 39 | echo "command=install" >> $GITHUB_OUTPUT 40 | echo "runner=yarn" >> $GITHUB_OUTPUT 41 | exit 0 42 | elif [ -f "${{ github.workspace }}/package.json" ]; then 43 | echo "manager=npm" >> $GITHUB_OUTPUT 44 | echo "command=ci" >> $GITHUB_OUTPUT 45 | echo "runner=npx --no-install" >> $GITHUB_OUTPUT 46 | exit 0 47 | else 48 | echo "Unable to determine package manager" 49 | exit 1 50 | fi 51 | - name: Setup Node 52 | uses: actions/setup-node@v4 53 | with: 54 | node-version: "20" 55 | cache: ${{ steps.detect-package-manager.outputs.manager }} 56 | - name: Setup Pages 57 | uses: actions/configure-pages@v5 58 | with: 59 | # Automatically inject basePath in your Next.js configuration file and disable 60 | # server side image optimization (https://nextjs.org/docs/api-reference/next/image#unoptimized). 61 | # 62 | # You may remove this line if you want to manage the configuration yourself. 63 | static_site_generator: next 64 | - name: Restore cache 65 | uses: actions/cache@v4 66 | with: 67 | path: | 68 | .next/cache 69 | # Generate a new cache whenever packages or source files change. 70 | key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }} 71 | # If source files changed but packages didn't, rebuild from a prior cache. 72 | restore-keys: | 73 | ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}- 74 | - name: Install dependencies 75 | run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }} 76 | - name: Build with Next.js 77 | run: ${{ steps.detect-package-manager.outputs.runner }} next build 78 | - name: Upload artifact 79 | uses: actions/upload-pages-artifact@v3 80 | with: 81 | path: ./out 82 | 83 | # Deployment job 84 | deploy: 85 | environment: 86 | name: github-pages 87 | url: ${{ steps.deployment.outputs.page_url }} 88 | runs-on: ubuntu-latest 89 | needs: build 90 | steps: 91 | - name: Deploy to GitHub Pages 92 | id: deployment 93 | uses: actions/deploy-pages@v4 94 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 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 37 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/.git 2 | **/node_modules 3 | **/package.json 4 | **/package-lock.json -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "editorconfig": true, 3 | "singleQuote": false, 4 | "jsxSingleQuote": false, 5 | "trailingComma": "all", 6 | "quoteProps": "as-needed" 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "scss.lint.unknownAtRules": "ignore", 3 | "css.lint.unknownAtRules": "ignore", 4 | "files.associations": { 5 | "*.css": "tailwindcss" 6 | }, 7 | "css.customData": [".vscode/tailwind.json"] 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/tailwind.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1.1, 3 | "atDirectives": [ 4 | { 5 | "name": "@tailwind", 6 | "description": "Use the `@tailwind` directive to insert Tailwind's `base`, `components`, `utilities` and `screens` styles into your CSS.", 7 | "references": [ 8 | { 9 | "name": "Tailwind Documentation", 10 | "url": "https://tailwindcss.com/docs/functions-and-directives#tailwind" 11 | } 12 | ] 13 | }, 14 | { 15 | "name": "@apply", 16 | "description": "Use the `@apply` directive to inline any existing utility classes into your own custom CSS. This is useful when you find a common utility pattern in your HTML that you’d like to extract to a new component.", 17 | "references": [ 18 | { 19 | "name": "Tailwind Documentation", 20 | "url": "https://tailwindcss.com/docs/functions-and-directives#apply" 21 | } 22 | ] 23 | }, 24 | { 25 | "name": "@responsive", 26 | "description": "You can generate responsive variants of your own classes by wrapping their definitions in the `@responsive` directive:\n```css\n@responsive {\n .alert {\n background-color: #E53E3E;\n }\n}\n```\n", 27 | "references": [ 28 | { 29 | "name": "Tailwind Documentation", 30 | "url": "https://tailwindcss.com/docs/functions-and-directives#responsive" 31 | } 32 | ] 33 | }, 34 | { 35 | "name": "@screen", 36 | "description": "The `@screen` directive allows you to create media queries that reference your breakpoints by **name** instead of duplicating their values in your own CSS:\n```css\n@screen sm {\n /* ... */\n}\n```\n…gets transformed into this:\n```css\n@media (min-width: 640px) {\n /* ... */\n}\n```\n", 37 | "references": [ 38 | { 39 | "name": "Tailwind Documentation", 40 | "url": "https://tailwindcss.com/docs/functions-and-directives#screen" 41 | } 42 | ] 43 | }, 44 | { 45 | "name": "@variants", 46 | "description": "Generate `hover`, `focus`, `active` and other **variants** of your own utilities by wrapping their definitions in the `@variants` directive:\n```css\n@variants hover, focus {\n .btn-brand {\n background-color: #3182CE;\n }\n}\n```\n", 47 | "references": [ 48 | { 49 | "name": "Tailwind Documentation", 50 | "url": "https://tailwindcss.com/docs/functions-and-directives#variants" 51 | } 52 | ] 53 | } 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AI SEO 2 | 3 | AI SEO screenshot 4 | 5 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 6 | 7 | ## Features 8 | 9 | - Modern, dark design 10 | - Animated with Framer Motion 11 | - Responsive layout 12 | - SEO-optimized 13 | - Cross-Browser Compatibility 14 | - Accessibility 15 | - Easy to Customize 16 | 17 | ## Getting Started 18 | 19 | First, To install the project dependencies, run: 20 | 21 | ```bash 22 | npm install 23 | # or 24 | yarn install 25 | # or 26 | pnpm install 27 | # or 28 | bun install 29 | ``` 30 | 31 | ## Usage 32 | 33 | After installation, you can start the development server: 34 | 35 | ```bash 36 | npm run dev 37 | # or 38 | yarn dev 39 | # or 40 | pnpm dev 41 | # or 42 | bun dev 43 | ``` 44 | 45 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 46 | 47 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 48 | 49 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load DM_Sans, a custom Google Font. 50 | 51 | ## Design 52 | 53 | You can view the design for this project on Figma: [AI Startup Landing Page](https://www.figma.com/design/XpZQogjrnUSWYceMccagvu/AI-Startup-Landing-Page?node-id=4007-684&t=7L89agO6vZJulren-1) 54 | 55 | ## Contributing 56 | 57 | Contributions are welcome! Please read the [contributing guidelines](CONTRIBUTING.md) first. 58 | 59 | ## License 60 | 61 | This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. 62 | -------------------------------------------------------------------------------- /Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/Screenshot.png -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | 3 | const nextConfig = { 4 | output: "standalone", 5 | webpack(config) { 6 | // Grab the existing rule that handles SVG imports 7 | const fileLoaderRule = config.module.rules.find((rule) => 8 | rule.test?.test?.(".svg"), 9 | ); 10 | 11 | config.module.rules.push( 12 | // Reapply the existing rule, but only for svg imports ending in ?url 13 | { 14 | ...fileLoaderRule, 15 | test: /\.svg$/i, 16 | resourceQuery: /url/, // *.svg?url 17 | }, 18 | // Convert all other *.svg imports to React components 19 | { 20 | test: /\.svg$/i, 21 | issuer: fileLoaderRule.issuer, 22 | resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] }, // exclude if *.svg?url 23 | use: ["@svgr/webpack"], 24 | }, 25 | ); 26 | 27 | // Modify the file loader rule to ignore *.svg, since we have it handled now. 28 | fileLoaderRule.exclude = /\.svg$/i; 29 | 30 | return config; 31 | }, 32 | }; 33 | 34 | export default nextConfig; 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ai-seo", 3 | "version": "1.0.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 | "@dotlottie/react-player": "^1.6.19", 13 | "@lottiefiles/dotlottie-react": "^0.8.7", 14 | "framer-motion": "^11.3.28", 15 | "next": "14.2.5", 16 | "react": "^18", 17 | "react-dom": "^18", 18 | "sharp": "^0.33.4" 19 | }, 20 | "devDependencies": { 21 | "@svgr/webpack": "^8.1.0", 22 | "@types/node": "^20", 23 | "@types/react": "^18", 24 | "@types/react-dom": "^18", 25 | "eslint": "^8", 26 | "eslint-config-next": "14.2.5", 27 | "postcss": "^8", 28 | "tailwind-merge": "^2.5.2", 29 | "tailwindcss": "^3.4.1", 30 | "typescript": "^5" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /public/assets/lottie/click.lottie: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/public/assets/lottie/click.lottie -------------------------------------------------------------------------------- /public/assets/lottie/stars.lottie: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/public/assets/lottie/stars.lottie -------------------------------------------------------------------------------- /public/assets/lottie/vroom.lottie: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/public/assets/lottie/vroom.lottie -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/src/app/favicon.ico -------------------------------------------------------------------------------- /src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import type { Metadata } from "next"; 3 | import { Inter } from "next/font/google"; 4 | import { twMerge } from "tailwind-merge"; 5 | import "@/styles/globals.css"; 6 | 7 | const inter = Inter({ subsets: ["latin"] }); 8 | 9 | export const metadata: Metadata = { 10 | title: "AI SEO | AI Startup Landing Page", 11 | description: "A landing page for an AI startup", 12 | }; 13 | 14 | export default function RootLayout({ 15 | children, 16 | }: Readonly<{ 17 | children: React.ReactNode; 18 | }>) { 19 | return ( 20 | 21 | 25 | {children} 26 | 27 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { CallToAction } from "@/sections/CallToAction"; 2 | import { Features } from "@/sections/Features"; 3 | import { Footer } from "@/sections/Footer"; 4 | import { Header } from "@/sections/Header"; 5 | import { Hero } from "@/sections/Hero"; 6 | import { LogoTicker } from "@/sections/LogoTicker"; 7 | import { Testimonials } from "@/sections/Testimonials"; 8 | 9 | export default function Home() { 10 | return ( 11 |
12 |
13 | 14 | 15 | 16 | 17 | 18 |
20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/assets/avatar-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/src/assets/avatar-1.png -------------------------------------------------------------------------------- /src/assets/avatar-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/src/assets/avatar-2.png -------------------------------------------------------------------------------- /src/assets/avatar-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/src/assets/avatar-3.png -------------------------------------------------------------------------------- /src/assets/avatar-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/src/assets/avatar-4.png -------------------------------------------------------------------------------- /src/assets/grid-lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/src/assets/grid-lines.png -------------------------------------------------------------------------------- /src/assets/icon-click.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icon-guage.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icon-menu.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/icon-stars.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Avatar1 } from "@/assets/avatar-1.png"; 2 | export { default as Avatar2 } from "@/assets/avatar-2.png"; 3 | export { default as Avatar3 } from "@/assets/avatar-3.png"; 4 | export { default as Avatar4 } from "@/assets/avatar-4.png"; 5 | export { default as GridLines } from "@/assets/grid-lines.png"; 6 | export { default as ClickIcon } from "@/assets/icon-click.svg"; 7 | export { default as GuageIcon } from "@/assets/icon-guage.svg"; 8 | export { default as MenuIcon } from "@/assets/icon-menu.svg"; 9 | export { default as StarsIcon } from "@/assets/icon-stars.svg"; 10 | export { default as AcmeLogo } from "@/assets/logo-acme.png"; 11 | export { default as ApexLogo } from "@/assets/logo-apex.png"; 12 | export { default as CelestialLogo } from "@/assets/logo-celestial.png"; 13 | export { default as EchoLogo } from "@/assets/logo-echo.png"; 14 | export { default as PulseLogo } from "@/assets/logo-pulse.png"; 15 | export { default as QuantumLogo } from "@/assets/logo-quantum.png"; 16 | export { default as Logo } from "@/assets/logo.svg"; 17 | export { default as ProductImage } from "@/assets/product-image.png"; 18 | export { default as SocialInstagram } from "@/assets/social-instagram.svg"; 19 | export { default as SocialX } from "@/assets/social-x.svg"; 20 | export { default as SocialYoutube } from "@/assets/social-youtube.svg"; 21 | export { default as StarsImage } from "@/assets/stars.png"; 22 | -------------------------------------------------------------------------------- /src/assets/logo-acme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/src/assets/logo-acme.png -------------------------------------------------------------------------------- /src/assets/logo-apex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/src/assets/logo-apex.png -------------------------------------------------------------------------------- /src/assets/logo-celestial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/src/assets/logo-celestial.png -------------------------------------------------------------------------------- /src/assets/logo-echo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/src/assets/logo-echo.png -------------------------------------------------------------------------------- /src/assets/logo-pulse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/src/assets/logo-pulse.png -------------------------------------------------------------------------------- /src/assets/logo-quantum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/src/assets/logo-quantum.png -------------------------------------------------------------------------------- /src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/product-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/src/assets/product-image.png -------------------------------------------------------------------------------- /src/assets/social-instagram.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/assets/social-x.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/social-youtube.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/stars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/src/assets/stars.png -------------------------------------------------------------------------------- /src/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faridvatani/ai-seo/cbe2a5060e5b442024be778e067c70d075ab8b39/src/components/.gitkeep -------------------------------------------------------------------------------- /src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC, PropsWithChildren } from "react"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | interface ButtonProps { 5 | classname?: string; 6 | } 7 | 8 | export const Button: FC> = ({ 9 | children, 10 | classname, 11 | }) => { 12 | return ( 13 | 27 | ); 28 | }; 29 | -------------------------------------------------------------------------------- /src/components/FeatureTab.tsx: -------------------------------------------------------------------------------- 1 | import { useRef, useEffect } from "react"; 2 | import { 3 | DotLottieCommonPlayer, 4 | DotLottiePlayer, 5 | } from "@dotlottie/react-player"; 6 | import { 7 | animate, 8 | motion, 9 | useMotionTemplate, 10 | useMotionValue, 11 | ValueAnimationTransition, 12 | } from "framer-motion"; 13 | import { ComponentPropsWithoutRef } from "react"; 14 | import { featuresTabs } from "@/data/data"; 15 | 16 | const FeatureTab = ( 17 | props: (typeof featuresTabs)[number] & 18 | ComponentPropsWithoutRef<"div"> & { selected: boolean }, 19 | ) => { 20 | const tabRef = useRef(null); 21 | const dotLottieRef = useRef(null); 22 | const xPercentage = useMotionValue(0); 23 | const yPercentage = useMotionValue(0); 24 | const maskImage = useMotionTemplate`radial-gradient(80px 80px at ${xPercentage}% ${yPercentage}%,black,transparent)`; 25 | 26 | useEffect(() => { 27 | if (!tabRef.current || !props.selected) { 28 | return; 29 | } 30 | xPercentage.set(0); 31 | yPercentage.set(0); 32 | 33 | const { height, width } = tabRef.current.getBoundingClientRect(); 34 | const circumference = height * 2 + width * 2; 35 | 36 | const times = [ 37 | 0, 38 | width / circumference, 39 | (width + height) / circumference, 40 | (width * 2 - height) / circumference, 41 | 1, 42 | ]; 43 | 44 | const options: ValueAnimationTransition = { 45 | times, 46 | duration: 4, 47 | repeat: Infinity, 48 | ease: "linear", 49 | repeatType: "loop", 50 | }; 51 | 52 | animate(xPercentage, [0, 100, 100, 0, 0], options); 53 | animate(yPercentage, [0, 0, 100, 100, 0], options); 54 | }, [props.selected, xPercentage, yPercentage]); 55 | 56 | const handleTabHover = () => { 57 | if (dotLottieRef.current === null) { 58 | return; 59 | } 60 | dotLottieRef.current.seek(0); 61 | dotLottieRef.current?.play(); 62 | }; 63 | 64 | return ( 65 |
71 | {props.selected && ( 72 | 78 | )} 79 |
80 | 86 |
87 | {props.title} 88 | {props.isNew && ( 89 | 90 | new 91 | 92 | )} 93 |
94 | ); 95 | }; 96 | 97 | export default FeatureTab; 98 | -------------------------------------------------------------------------------- /src/data/data.ts: -------------------------------------------------------------------------------- 1 | import { Avatar1, Avatar2, Avatar3, Avatar4 } from "@/assets"; 2 | 3 | export const featuresTabs = [ 4 | { 5 | icon: "./assets/lottie/vroom.lottie", 6 | title: "User-friendly dashboard", 7 | isNew: false, 8 | backgroundPositionX: 0, 9 | backgroundPositionY: 0, 10 | backgroundSizeX: 150, 11 | }, 12 | { 13 | icon: "./assets/lottie/click.lottie", 14 | title: "One-click optimization", 15 | isNew: false, 16 | backgroundPositionX: 98, 17 | backgroundPositionY: 100, 18 | backgroundSizeX: 135, 19 | }, 20 | { 21 | icon: "./assets/lottie/stars.lottie", 22 | title: "Smart keyword generator", 23 | isNew: true, 24 | backgroundPositionX: 100, 25 | backgroundPositionY: 27, 26 | backgroundSizeX: 177, 27 | }, 28 | ]; 29 | 30 | export const testimonials = [ 31 | { 32 | text: "“This product has completely transformed how I manage my projects and deadlines”", 33 | name: "Sophia Perez", 34 | title: "Director @ Quantum", 35 | avatarImg: Avatar1, 36 | }, 37 | { 38 | text: "“These AI tools have completely revolutionized our SEO entire strategy overnight”", 39 | name: "Jamie Lee", 40 | title: "Founder @ Pulse", 41 | avatarImg: Avatar2, 42 | }, 43 | { 44 | text: "“The user interface is so intuitive and easy to use, it has saved us countless hours”", 45 | name: "Alisa Hester", 46 | title: "Product @ Innovate", 47 | avatarImg: Avatar3, 48 | }, 49 | { 50 | text: "“Our team's productivity has increased significantly since we started using this tool”", 51 | name: "Alec Whitten", 52 | title: "CTO @ Tech Solutions", 53 | avatarImg: Avatar4, 54 | }, 55 | ]; 56 | -------------------------------------------------------------------------------- /src/hooks/useRelativeMousePosition.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, RefObject } from "react"; 2 | import { useMotionValue } from "framer-motion"; 3 | 4 | const useRelativeMousePosition = (to: RefObject) => { 5 | const mouseX = useMotionValue(0); 6 | const mouseY = useMotionValue(0); 7 | 8 | const updateMousePosition = (event: MouseEvent) => { 9 | if (!to.current) { 10 | return; 11 | } 12 | const { top, left } = to.current.getBoundingClientRect(); 13 | mouseX.set(event.x - left); 14 | mouseY.set(event.y - top); 15 | }; 16 | 17 | useEffect(() => { 18 | window.addEventListener("mousemove", updateMousePosition); 19 | 20 | return () => { 21 | window.removeEventListener("mousemove", updateMousePosition); 22 | }; 23 | }, []); 24 | 25 | return [mouseX, mouseY]; 26 | }; 27 | 28 | export default useRelativeMousePosition; 29 | -------------------------------------------------------------------------------- /src/sections/CallToAction.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { Button } from "@/components/Button"; 3 | import { StarsImage, GridLines } from "@/assets"; 4 | import { 5 | motion, 6 | useMotionTemplate, 7 | useScroll, 8 | useTransform, 9 | } from "framer-motion"; 10 | import { useRef } from "react"; 11 | import useRelativeMousePosition from "@/hooks/useRelativeMousePosition"; 12 | 13 | export const CallToAction = () => { 14 | const sectionRef = useRef(null); 15 | const borderedDivRef = useRef(null); 16 | const { scrollYProgress } = useScroll({ 17 | target: sectionRef, 18 | offset: ["start end", "end start"], 19 | }); 20 | 21 | const backgroundPositionY = useTransform( 22 | scrollYProgress, 23 | [0, 1], 24 | [-300, 300], 25 | ); 26 | 27 | const [mouseX, mouseY] = useRelativeMousePosition(borderedDivRef); 28 | const maskImage = useMotionTemplate`radial-gradient(50% 50% at ${mouseX}px ${mouseY}px, black, transparent)`; 29 | 30 | return ( 31 |
32 |
33 | 49 |
55 | 62 |
63 |

64 | AI-driven SEO for everyone. 65 |

66 |

67 | Achieve clear, impactful results without the complexity. 68 |

69 |
70 | 71 |
72 |
73 |
74 |
75 |
76 | ); 77 | }; 78 | -------------------------------------------------------------------------------- /src/sections/Features.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { ProductImage } from "@/assets"; 3 | import { featuresTabs } from "@/data/data"; 4 | import { 5 | animate, 6 | motion, 7 | useMotionTemplate, 8 | useMotionValue, 9 | ValueAnimationTransition, 10 | } from "framer-motion"; 11 | import { useState } from "react"; 12 | import FeatureTab from "@/components/FeatureTab"; 13 | 14 | export const Features = () => { 15 | const [currentTab, setCurrentTab] = useState(0); 16 | const backgroundPositionX = useMotionValue( 17 | featuresTabs[0].backgroundPositionX, 18 | ); 19 | const backgroundPositionY = useMotionValue( 20 | featuresTabs[0].backgroundPositionY, 21 | ); 22 | const backgroundSizeX = useMotionValue(featuresTabs[0].backgroundSizeX); 23 | 24 | const backgroundPosition = useMotionTemplate`${backgroundPositionX}% ${backgroundPositionY}%`; 25 | const backgroundSize = useMotionTemplate`${backgroundSizeX}% auto`; 26 | 27 | const handleSelectTab = (tabIndex: number) => { 28 | setCurrentTab(tabIndex); 29 | 30 | const animateOptions: ValueAnimationTransition = { 31 | duration: 2, 32 | ease: "easeInOut", 33 | }; 34 | 35 | animate( 36 | backgroundSizeX, 37 | [backgroundSizeX.get(), 100, featuresTabs[tabIndex].backgroundSizeX], 38 | animateOptions, 39 | ); 40 | 41 | animate( 42 | backgroundPositionX, 43 | [backgroundPositionX.get(), featuresTabs[tabIndex].backgroundPositionX], 44 | animateOptions, 45 | ); 46 | 47 | animate( 48 | backgroundPositionY, 49 | [backgroundPositionY.get(), featuresTabs[tabIndex].backgroundPositionY], 50 | animateOptions, 51 | ); 52 | }; 53 | 54 | return ( 55 |
56 |
57 |

58 | Elevate your SEO efforts. 59 |

60 |

61 | From small startups to large enterprises, our AI-driven tool has 62 | revolutionized the way businesses approach SEO. 63 |

64 |
65 | {featuresTabs.map((tab, tabIndex) => ( 66 | handleSelectTab(tabIndex)} 70 | selected={currentTab === tabIndex} 71 | /> 72 | ))} 73 |
74 |
75 | 83 |
84 |
85 |
86 | ); 87 | }; 88 | -------------------------------------------------------------------------------- /src/sections/Footer.tsx: -------------------------------------------------------------------------------- 1 | import { Logo, SocialX, SocialInstagram, SocialYoutube } from "@/assets"; 2 | import Link from "next/link"; 3 | 4 | const navItems = [ 5 | { href: "#", title: "Features" }, 6 | { href: "#", title: "Developers" }, 7 | { href: "#", title: "Company" }, 8 | { href: "#", title: "Blog" }, 9 | { href: "#", title: "Changelog" }, 10 | ]; 11 | 12 | export const Footer = () => { 13 | return ( 14 |
15 |
16 |
17 |
18 | 19 | AI Startup Landing Page 20 |
21 | 32 |
33 | 34 | 35 | 36 |
37 |
38 |
39 |
40 | ); 41 | }; 42 | -------------------------------------------------------------------------------- /src/sections/Header.tsx: -------------------------------------------------------------------------------- 1 | import { Logo, MenuIcon } from "@/assets"; 2 | import { Button } from "@/components/Button"; 3 | import Link from "next/link"; 4 | 5 | const navItems = [ 6 | { href: "#", title: "Features" }, 7 | { href: "#", title: "Developers" }, 8 | { href: "#", title: "Pricing" }, 9 | { href: "#", title: "Changelog" }, 10 | ]; 11 | 12 | export const Header = () => { 13 | return ( 14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | 22 |
23 |
24 |
25 | 36 |
37 |
38 | 39 | 40 |
41 |
42 |
43 |
44 | ); 45 | }; 46 | -------------------------------------------------------------------------------- /src/sections/Hero.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { Button } from "@/components/Button"; 3 | import { StarsImage } from "@/assets"; 4 | import { motion, useScroll, useTransform } from "framer-motion"; 5 | import { useRef } from "react"; 6 | 7 | export const Hero = () => { 8 | const sectionRef = useRef(null); 9 | const { scrollYProgress } = useScroll({ 10 | target: sectionRef, 11 | offset: ["start end", "end start"], 12 | }); 13 | 14 | const backgroundPositionY = useTransform( 15 | scrollYProgress, 16 | [0, 1], 17 | [-300, 300], 18 | ); 19 | 20 | return ( 21 | 34 |
35 | {/* Start Planet */} 36 |
37 | {/* End Planet */} 38 | {/* Start Ring 1 */} 39 | 54 |
55 |
56 |
57 |
58 |
59 |
60 | {/* End Ring 1 */} 61 | {/* Start Ring 2 */} 62 | 77 | {/* End Ring 2 */} 78 | {/* Start Ring 3 */} 79 | 94 |
95 |
96 |
97 | {/* End Ring 3 */} 98 |
99 |

100 | AI SEO 101 |

102 |

103 | Elevate your site's visibility effortlessly with AI, where smart 104 | technology meets user-friendly SEO tools. 105 |

106 |
107 | 108 |
109 |
110 |
111 | ); 112 | }; 113 | -------------------------------------------------------------------------------- /src/sections/LogoTicker.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { 3 | AcmeLogo, 4 | ApexLogo, 5 | CelestialLogo, 6 | QuantumLogo, 7 | PulseLogo, 8 | EchoLogo, 9 | } from "@/assets"; 10 | import { motion } from "framer-motion"; 11 | import Image from "next/image"; 12 | 13 | const logos = [ 14 | AcmeLogo, 15 | PulseLogo, 16 | EchoLogo, 17 | CelestialLogo, 18 | ApexLogo, 19 | QuantumLogo, 20 | ]; 21 | 22 | export const LogoTicker = () => { 23 | return ( 24 |
25 |
26 |
27 |
28 |

Trusted by top innovative teams

29 |
30 |
31 | 41 | {[...logos, ...logos].map((logo, index) => ( 42 | Logo Ticker 50 | ))} 51 | 52 |
53 |
54 |
55 |
56 | ); 57 | }; 58 | -------------------------------------------------------------------------------- /src/sections/Testimonials.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { testimonials } from "@/data/data"; 3 | import { motion } from "framer-motion"; 4 | import Image from "next/image"; 5 | 6 | export const Testimonials = () => { 7 | return ( 8 |
9 |
10 |

11 | Beyond Expectations. 12 |

13 |

14 | Our revolutionary AI SEO tools have transformed our clients' 15 | strategies. 16 |

17 |
18 | 32 | {[...testimonials, ...testimonials].map((testimonial, index) => ( 33 |
37 | 38 | {testimonial.text} 39 | 40 |
41 |
42 | {`Avatar 47 |
48 |
49 | {testimonial.name} 50 | 51 | {testimonial.title} 52 | 53 |
54 |
55 |
56 | ))} 57 |
58 |
59 |
60 |
61 | ); 62 | }; 63 | -------------------------------------------------------------------------------- /src/styles/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | const config: Config = { 4 | content: [ 5 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./src/sections/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 8 | ], 9 | theme: { 10 | container: { 11 | center: true, 12 | padding: { 13 | DEFAULT: "20px", 14 | lg: "80px", 15 | }, 16 | screens: { 17 | sm: "375px", 18 | md: "768px", 19 | lg: "1200px", 20 | }, 21 | }, 22 | screens: { 23 | sm: "375px", 24 | md: "768px", 25 | lg: "1200px", 26 | }, 27 | extend: {}, 28 | }, 29 | plugins: [], 30 | }; 31 | export default config; 32 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ], 20 | "paths": { 21 | "@/*": ["./src/*"] 22 | } 23 | }, 24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 25 | "exclude": ["node_modules"] 26 | } 27 | --------------------------------------------------------------------------------