diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..bdaeff9 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +demo.artureanec.com 2/ diff --git a/AGENTS.md b/AGENTS.md index 8bd0e39..9ddb5ac 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,3 +3,287 @@ This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices. + +# Code Maintainability Rules + +This project must remain understandable by: + +- Freshers +- Frontend developers +- Backend developers +- New team members + +Rules: + +1. No component may exceed 400 lines. +2. No page file may exceed 300 lines. +3. No CSS file may exceed 500 lines. +4. Prefer Tailwind utilities over custom CSS. +5. Avoid duplicated styles. +6. Create reusable UI components. +7. Use meaningful file names. +8. Keep folder depth shallow. +9. Avoid massive utility/helper files. +10. Every component should have a single responsibility. + +If a file becomes too large, split it into smaller components immediately. + +Code readability is more important than clever implementations. + +# Design System Rules + +## Single Source of Truth + +Common design values must be centralized. + +Do NOT hardcode the same values across multiple sections. + +Create shared design tokens for: + +* Colors +* Typography +* Border Radius +* Shadows +* Container Widths +* Section Spacing +* Button Styles +* Animation Presets + +## Color System + +All colors must come from a shared theme file. + +Examples: + +* Primary +* Secondary +* Accent +* Background +* Surface +* Border + +Do not repeat hex values throughout the project. + +Changing a color in one place should update the entire site. + +## Typography System + +Create shared typography styles. + +Examples: + +* Hero Title +* Section Title +* Card Title +* Body Text +* Small Text + +Do not redefine font sizes in every section. + +Changing typography tokens should update all matching sections. + +## Shared Components + +If multiple sections use the same UI pattern: + +* Card +* Button +* Badge +* Section Header +* CTA Block +* Statistic Counter + +Create one reusable component. + +Do not duplicate markup. + +A change in one component should update every instance. + +## Shared Section Layout + +Create common section spacing tokens. + +Examples: + +* sectionPaddingY +* sectionPaddingX +* containerWidth + +All sections must use the same spacing system. + +Avoid custom padding per section unless intentionally required by the reference. + +## Consistent Container System + +All major sections must use the same container. + +Examples: + +* Container +* PageContainer +* SectionContainer + +Do not create unique widths for every section. + +## Shared Animation System + +Create reusable animation presets. + +Examples: + +* fadeUp +* staggerChildren +* scaleIn +* slideIn + +Do not redefine animations in every component. + +## Shared Image System + +Common image styles should be reusable. + +Examples: + +* cardImage +* heroImage +* avatarImage + +Avoid repeating image styling logic. + +## Global Change Rule + +If the same pattern exists in multiple sections, do not update only one section. + +Examples: + +* Hero Title +* About Title +* Feature Title + +Update the shared source. + +The change must automatically propagate everywhere the pattern is used. + +## Spacing Consistency Rule + +Top, Bottom, Left, and Right spacing must follow the same design system. + +Avoid random values such as: + +* 72px +* 94px +* 113px +* 147px + +Use predefined spacing tokens only. + +The entire site should feel visually consistent. + +# AGENTS.md + +## Mission + +Recreate the Aiero Home 9 experience with maximum visual fidelity while keeping the codebase maintainable and production-ready. + +## Agent Behavior + +Before making changes: + +* Analyze existing component +* Compare against reference +* Identify exact mismatch +* Apply minimal fix + +Do not perform large rewrites unless explicitly requested. + +## Priority Order + +1. Layout Accuracy +2. Spacing Accuracy +3. Typography Accuracy +4. Image Placement +5. Responsiveness +6. Animation +7. Refactoring + +## Hero Analysis Checklist + +Verify: + +* Hero height +* Hero width +* Artwork scale +* Artwork position +* Heading width +* Heading line breaks +* CTA placement +* Scroll indicator position +* Navbar alignment + +## Card Analysis Checklist + +Verify: + +* Border radius +* Padding +* Image crop +* Text spacing +* Card proportions +* Responsive behavior + +## Forbidden Actions + +Do NOT: + +* Replace sections without approval +* Change color system globally +* Introduce new layouts +* Remove existing functionality +* Rewrite working components + +## Preferred Workflow + +Step 1: +Identify mismatch. + +Step 2: +Describe mismatch. + +Step 3: +Implement targeted fix. + +Step 4: +Verify visually. + +Step 5: +Move to next issue. + +## Visual Fidelity Standard + +Target: + +95%+ match to reference. + +Every change should improve: + +* Layout +* Alignment +* Proportions +* Visual balance + +Avoid subjective redesign decisions. + +Reference fidelity is more important than personal preference. + +## Code Quality Rules + +* TypeScript strict +* Reusable components +* Clean props +* No duplicated code +* No inline magic values +* Use Tailwind consistently + +## Final Goal + +Build a production-quality Next.js implementation that visually matches Aiero Home 9 as closely as possible while maintaining clean architecture and long-term maintainability. diff --git a/CLAUDE.md b/CLAUDE.md index 43c994c..7c5fe9c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1 +1,147 @@ @AGENTS.md +# CLAUDE.md + +## Project Overview + +This project is a high-fidelity recreation of the Aiero Home 9 landing page using Next.js App Router, TypeScript, Tailwind CSS, and Framer Motion. + +The goal is NOT to redesign the page. + +The goal is to accurately reproduce the visual hierarchy, layout structure, spacing system, card architecture, typography scale, and responsive behavior of the reference implementation. + +## Core Rules + +1. Preserve visual fidelity. +2. Avoid unnecessary redesigns. +3. Prefer refinement over replacement. +4. Maintain existing component architecture. +5. Never replace working sections with completely new layouts. + +## Design System Rules + +Common design decisions must come from shared sources, not repeated one-off values. + +Centralize: + +* Colors +* Typography +* Border radius +* Shadows +* Container widths +* Section spacing +* Button styles +* Animation presets +* Image styles + +Use reusable components for repeated patterns such as cards, buttons, badges, section headers, CTA blocks, and statistic counters. + +All major sections should use the shared container and spacing system. Avoid random spacing values such as 72px, 94px, 113px, or 147px unless the reference requires a deliberate exception. + +When the same pattern appears in multiple sections, update the shared token, component, or preset so the change propagates everywhere. + +## Design Philosophy + +The homepage is: + +* Editorial +* Card-driven +* Visual-first +* Premium AI agency +* Image-heavy +* Modern but minimal + +Avoid: + +* Generic SaaS layouts +* Dashboard-first designs +* Startup template aesthetics +* Excessive gradients +* Excessive glassmorphism + +## Hero Section Requirements + +Hero is the most important section. + +Must maintain: + +* Large background artwork +* Left aligned content +* Vertical Scroll Down element +* Large heading +* Compact CTA + +Hero artwork should dominate visual composition. + +Target ratio: + +70% visual +30% content + +## Card Layout Rules + +Cards should: + +* Use large border radii +* Have consistent spacing +* Maintain editorial proportions +* Feel like magazine blocks + +Do not: + +* Make all cards equal height +* Convert cards into dashboard widgets +* Add unnecessary statistics + +## Typography Rules + +Headings: + +* Strong +* Bold +* Editorial + +Body text: + +* Simple +* Readable +* Secondary + +Avoid oversized line lengths. + +## Animations + +Use subtle animations only. + +Allowed: + +* Fade up +* Hover lift +* Opacity transitions +* Small parallax + +Avoid: + +* Excessive motion +* Heavy GSAP timelines +* Distracting effects + +## Responsive Rules + +Desktop design is source of truth. + +Then adapt: + +Desktop → Tablet → Mobile + +Never design mobile first and then stretch to desktop. + +## Development Rules + +Before modifying a section: + +1. Inspect existing implementation. +2. Compare with reference. +3. Make minimal changes. +4. Preserve working behavior. + +Always prefer small iterative improvements. diff --git a/app/globals.css b/app/globals.css index a2dc41e..1e7ac9f 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,26 +1,311 @@ @import "tailwindcss"; :root { - --background: #ffffff; - --foreground: #171717; + /* ── Aiero color tokens (extracted from source) ── */ + --aiero-bg-dark: #1F1F1F; + --aiero-bg-card-dark: #282828; + --aiero-bg-card-border: #3F3F3F; + --aiero-accent-teal: #45D0BD; + --aiero-accent-blue: #44B6E9; + --aiero-accent-red: #EF6464; + --aiero-accent-red-hover: #F57E7E; + --aiero-purple-start: #8258C8; + --aiero-purple-mid: #6766C8; + --aiero-purple-end: #2C84C8; + --aiero-card-purple: #343F78; + --aiero-card-purple-2: #56619E; + --aiero-card-lavender: #AC8DE0; + --aiero-text-muted: #87899B; + + /* button gradient angles */ + --button-border-gradient-angle: 92deg; + --button-gradient-colorstop-1: 0%; + --button-gradient-colorstop-2: 100%; } @theme inline { - --color-background: var(--background); - --color-foreground: var(--foreground); - --font-sans: var(--font-geist-sans); - --font-mono: var(--font-geist-mono); + --color-background: #ffffff; + --color-foreground: #1F1F1F; + --color-aiero-dark: #1F1F1F; + --color-aiero-card-dark: #282828; + --color-aiero-card-border: #3F3F3F; + --color-aiero-teal: #45D0BD; + --color-aiero-blue: #44B6E9; + --color-aiero-red: #EF6464; + --color-aiero-red-hover: #F57E7E; + --color-aiero-purple-start: #8258C8; + --color-aiero-purple-mid: #6766C8; + --color-aiero-purple-end: #2C84C8; + --color-aiero-card-purple: #343F78; + --color-aiero-card-purple-2: #56619E; + --color-aiero-card-lavender: #AC8DE0; + --color-aiero-text-muted: #87899B; + + --font-sans: var(--font-manrope), ui-sans-serif, system-ui, sans-serif; + --font-sora: var(--font-sora), sans-serif; + --font-dm-sans: var(--font-dm-sans), sans-serif; } -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } +/* ── Base resets ── */ +* { + box-sizing: border-box; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +html { + scroll-behavior: smooth; + background: #ffffff; } body { - background: var(--background); - color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; + min-height: 100vh; + overflow-x: hidden; + background: #ffffff; + color: #1F1F1F; + font-family: var(--font-manrope), ui-sans-serif, system-ui, sans-serif; + font-size: 16px; + line-height: 1.6; +} + +a, +button { + -webkit-tap-highlight-color: transparent; +} + +/* ── Aiero button base ── */ +.aiero-button { + display: inline-flex; + align-items: center; + gap: 8px; + font-family: var(--font-sora), sans-serif; + text-decoration: none; + position: relative; + overflow: hidden; + transition: all 0.3s ease; + cursor: pointer; + white-space: nowrap; +} + +.aiero-button .button-inner { + position: absolute; + inset: 0; + border-radius: inherit; + pointer-events: none; +} + +/* Solid variant */ +.aiero-button-solid { + border-style: solid; + border-width: 1px; +} + +/* Gradient border variant */ +.aiero-button-gradient-border { + background: transparent; + border: none; + position: relative; + z-index: 0; +} + +.aiero-button-gradient-border::after { + content: ""; + position: absolute; + inset: 0; + border-radius: inherit; + padding: 1.5px; + background: linear-gradient( + var(--button-border-gradient-angle), + var(--aiero-accent-teal) var(--button-gradient-colorstop-1), + var(--aiero-accent-blue) var(--button-gradient-colorstop-2) + ); + -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; + pointer-events: none; + z-index: -1; +} + +.aiero-button-gradient-border .button-inner::before { + content: ""; + position: absolute; + inset: 0; + border-radius: inherit; + background: transparent; + transition: all 0.3s ease; +} + +.aiero-button-gradient-border .button-inner::after { + content: ""; + position: absolute; + inset: 0; + border-radius: inherit; + background: linear-gradient( + var(--button-border-gradient-angle), + var(--aiero-accent-teal) var(--button-gradient-colorstop-1), + var(--aiero-accent-blue) var(--button-gradient-colorstop-2) + ); + opacity: 0; + transition: opacity 0.3s ease; +} + +.aiero-button-gradient-border:hover .button-inner::after { + opacity: 1; +} + +.aiero-button-gradient-border:hover { + color: #333333; +} + +/* Gradient fill variant */ +.aiero-button-gradient-fill { + background: linear-gradient( + var(--button-border-gradient-angle), + var(--aiero-accent-teal) var(--button-gradient-colorstop-1), + var(--aiero-accent-blue) var(--button-gradient-colorstop-2) + ); + border: none; + color: #ffffff; +} + +.aiero-button-gradient-fill::after { + content: ""; + position: absolute; + inset: 0; + border-radius: inherit; + padding: 1.5px; + background: linear-gradient( + var(--button-border-gradient-angle), + var(--aiero-accent-teal) var(--button-gradient-colorstop-1), + var(--aiero-accent-blue) var(--button-gradient-colorstop-2) + ); + -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; + pointer-events: none; + z-index: -1; +} + +/* ── Gradient text ── */ +.gradient-text-purple { + background: linear-gradient(103deg, #8258C8 0%, #2C84C8 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.gradient-text-counter { + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +/* ── Icon decoration (curved corners) ── */ +.icon-decoration { + position: relative; +} + +.icon-decoration .icon-inner { + position: relative; + z-index: 1; +} + +.icon-decoration::before, +.icon-decoration::after { + content: ""; + position: absolute; + width: 20px; + height: 20px; + background: transparent; +} + +/* ── Marquee animation ── */ +@keyframes marquee { + 0% { + transform: translateX(0); + } + 100% { + transform: translateX(-50%); + } +} + +.animate-marquee { + animation: marquee 15s linear infinite; +} + +/* ── Counter animation ── */ +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* ── Aiero heading animation ── */ +@keyframes headingReveal { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.animate-heading-reveal { + animation: headingReveal 0.8s ease-out forwards; +} + +/* ── Scroll down button decoration ── */ +.scroll-btn-decoration { + position: relative; +} + +.scroll-btn-decoration::before, +.scroll-btn-decoration::after { + content: ""; + position: absolute; + width: 20px; + height: 20px; + background: transparent; +} + +.scroll-btn-decoration::before { + top: -20px; + left: 0; + border-bottom-left-radius: 20px; + box-shadow: 0 20px 0 0 #ffffff; +} + +.scroll-btn-decoration::after { + bottom: -20px; + left: 0; + border-top-left-radius: 20px; + box-shadow: 0 -20px 0 0 #ffffff; +} + +/* ── Subheading tag ── */ +.aiero-subheading { + display: inline-flex; + align-items: center; + gap: 10px; + font-family: var(--font-sora), sans-serif; + font-size: 12px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.1em; + margin-bottom: 16px; + position: relative; +} + +.aiero-subheading::before { + content: ""; + width: 30px; + height: 1px; + background: currentColor; } diff --git a/app/layout.tsx b/app/layout.tsx index 976eb90..f4cd4d7 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,20 +1,29 @@ import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; +import { Manrope, Sora, DM_Sans } from "next/font/google"; import "./globals.css"; -const geistSans = Geist({ - variable: "--font-geist-sans", +const manrope = Manrope({ + variable: "--font-manrope", subsets: ["latin"], + weight: ["400", "500", "600", "700"], }); -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", +const sora = Sora({ + variable: "--font-sora", subsets: ["latin"], + weight: ["400", "500", "600", "700"], +}); + +const dmSans = DM_Sans({ + variable: "--font-dm-sans", + subsets: ["latin"], + weight: ["400", "500", "600", "700"], }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Home 9 – Aiero", + description: + "Revolutionizing businesses with cutting-edge AI solutions and groundbreaking innovation. Aiero – AI agency committed to transforming businesses.", }; export default function RootLayout({ @@ -25,9 +34,9 @@ export default function RootLayout({ return ( - {children} + {children} ); } diff --git a/app/page.tsx b/app/page.tsx index 3f36f7c..b8400d9 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,65 +1,21 @@ -import Image from "next/image"; +import { Navbar } from "@/components/aiero/Navbar"; +import { HeroSection } from "@/components/aiero/HeroSection"; +import { CardsGrid } from "@/components/aiero/CardsGrid"; +import { PossibilitiesSection } from "@/components/aiero/PossibilitiesSection"; +import { MarqueeStrip } from "@/components/aiero/MarqueeStrip"; +import { FeaturesSection } from "@/components/aiero/FeaturesSection"; export default function Home() { return ( -
-
- Next.js logo -
-

- To get started, edit the page.tsx file. -

-

- Looking for a starting point or more instructions? Head over to{" "} - - Templates - {" "} - or the{" "} - - Learning - {" "} - center. -

-
-
- - Vercel logomark - Deploy Now - - - Documentation - -
-
-
+
+
+ +
+ + + + + +
); } diff --git a/components/aiero/CardsGrid.tsx b/components/aiero/CardsGrid.tsx new file mode 100644 index 0000000..871e8f8 --- /dev/null +++ b/components/aiero/CardsGrid.tsx @@ -0,0 +1,125 @@ +import { CardHeading, IconButton } from "@/components/shared/CardShared"; +import { ChartIcon } from "@/components/shared/icons/ChartIcon"; +import { Counter } from "@/components/shared/Counter"; + +export function CardsGrid() { + return ( +
+
+ + {/* Card 1 */} +
+
+ +
+ + Solutions + + + Plugins + +
+ +
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ + +
+ + {/* Card 2 */} +
+
+
+ +
+
+ +
+ + + +

+ Cobra opaleye gray reef shark bluntnose minnow. +

+
+ + +
+ + {/* Card 3 (spans 2 columns) */} + +
+ ); +} diff --git a/components/aiero/FeaturesSection.tsx b/components/aiero/FeaturesSection.tsx new file mode 100644 index 0000000..2be7db0 --- /dev/null +++ b/components/aiero/FeaturesSection.tsx @@ -0,0 +1,125 @@ +import { CardHeading, IconButton } from "@/components/shared/CardShared"; +import { Counter } from "@/components/shared/Counter"; + +export function FeaturesSection() { + return ( +
+
+ {/* Top text and separator */} +
+
+

+ AI Solutions that drive success +

+
+ + {/* Feature Cards Grid */} +
+ + {/* Card 1 - Left */} +
+
+
+ +
+ + +
    +
  • + + Advanced analytics processing +
  • +
  • + + Real-time data synchronization +
  • +
  • + + Secure API endpoints +
  • +
+
+ + +
+ + {/* Card 2 - Right */} +
+
+ +
+ + + +
+ +
+ +

+ Cobra opaleye gray reef shark bluntnose minnow. Triggerfish bango guppy opah sunfish bluntnose knifefish upside-down catfish. +

+
+ + +
+ + {/* Card 3 - Bottom Full Width */} +
+
+ +
+
+ +
+ +
+ + +
+
+
+ +
+
+
+ ); +} diff --git a/components/aiero/HeroSection.tsx b/components/aiero/HeroSection.tsx new file mode 100644 index 0000000..6e5829e --- /dev/null +++ b/components/aiero/HeroSection.tsx @@ -0,0 +1,86 @@ + +export function HeroSection() { + return ( +
+ {/* Scroll Down button — vertical, left side */} +
+ + + Scroll down + + + + + +
+ + {/* Hero container with background */} +
+ + {/* Hero content */} +
+
+ {/* Heading */} +

+ Revolutionizing businesses with cutting-edge AI solutions and + groundbreaking innovation +

+ + {/* Subtitle */} +
+

+ Mummichog paradise fish! Triggerfish bango guppy opah sunfish + bluntnose knifefish upside-down catfish cobia spookfish convict + cichlid. +

+
+ + {/* CTA Button */} +
+ + Discover + + + + + +
+
+
+ + {/* Scroll anchor */} + +
+ ); +} diff --git a/components/aiero/MarqueeStrip.tsx b/components/aiero/MarqueeStrip.tsx new file mode 100644 index 0000000..e6dcaa2 --- /dev/null +++ b/components/aiero/MarqueeStrip.tsx @@ -0,0 +1,30 @@ +export function MarqueeStrip() { + return ( +
+
+ {/* Marquee track 1 */} +
+ {[...Array(6)].map((_, i) => ( +
+ + Artificial Intelligence + + +
+ ))} +
+ {/* Marquee track 2 (seamless loop) */} +
+ {[...Array(6)].map((_, i) => ( +
+ + Artificial Intelligence + + +
+ ))} +
+
+
+ ); +} diff --git a/components/aiero/Navbar.tsx b/components/aiero/Navbar.tsx new file mode 100644 index 0000000..7cb247c --- /dev/null +++ b/components/aiero/Navbar.tsx @@ -0,0 +1,102 @@ +"use client"; + +import { useState } from "react"; +import Image from "next/image"; +import { navigationData } from "@/data/navigation"; +import { SearchIcon } from "@/components/shared/icons/SearchIcon"; + +export function Navbar() { + const [openDropdown, setOpenDropdown] = useState(null); + + return ( +
+ {/* Logo */} + + Aiero + + + {/* Navigation */} + + + {/* Right Icons */} +
+ + + + + + + + Log in + + + + Get in Touch + + + + {/* Mobile menu button */} + +
+
+ ); +} diff --git a/components/aiero/PossibilitiesSection.tsx b/components/aiero/PossibilitiesSection.tsx new file mode 100644 index 0000000..f639e78 --- /dev/null +++ b/components/aiero/PossibilitiesSection.tsx @@ -0,0 +1,88 @@ +import { AieroButton } from "@/components/shared/AieroButton"; +import { Counter } from "@/components/shared/Counter"; +import { IconBox } from "@/components/shared/IconBox"; +import { OrbitIcon, FanIcon, CirclesIcon, ExpandIcon } from "@/components/shared/icons/PossibilityIcons"; + +export function PossibilitiesSection() { + return ( +
+
+ + {/* Left Column */} +
+ + Possibilities + + +

+ Explore limitless possibilities with Aiero AI +

+ +

+ Guppy siamese fighting fish, round stingray roach, sand tiger yellow weaver fish. Longnose lancetfish mooneye opah ghost fish. +

+ + + Explore more + + +
+ +
+
+ + {/* Right Column */} +
+ } + title="Cutting-edge technology" + description="Integration of state-of-the-art AI algorithms, including deep learning, natural language processing." + hasBorder={true} + /> + } + title="Tailored solutions" + description="Custom design and development of neural network architectures tailored to specific business needs." + hasBorder={true} + /> + } + title="Training and workshops" + description="Custom design and development of neural network architectures tailored to specific business needs and objectives." + hasBorder={true} + /> + } + title="AI-powered design" + description="Integration of state-of-the-art AI algorithms, including deep learning, natural language processing." + hasBorder={false} + /> +
+ +
+
+ ); +} diff --git a/components/shared/AieroButton.tsx b/components/shared/AieroButton.tsx new file mode 100644 index 0000000..89a40bd --- /dev/null +++ b/components/shared/AieroButton.tsx @@ -0,0 +1,51 @@ +import { ArrowIcon } from "@/components/shared/icons/ArrowIcon"; + +type ButtonVariant = "solid" | "outline" | "gradient-border" | "gradient-fill" | "simple"; + +interface AieroButtonProps { + href?: string; + variant?: ButtonVariant; + children: React.ReactNode; + className?: string; + showArrow?: boolean; + target?: string; + onClick?: () => void; +} + +export function AieroButton({ + href = "#", + variant = "solid", + children, + className = "", + showArrow = true, + target, + onClick, +}: AieroButtonProps) { + const baseClasses = "aiero-button"; + + const variantClasses: Record = { + solid: "aiero-button-solid", + outline: "aiero-button-solid", + "gradient-border": "aiero-button-gradient-border", + "gradient-fill": "aiero-button-gradient-fill", + simple: "", + }; + + const combined = `${baseClasses} ${variantClasses[variant]} ${className}`; + + return ( + + {children} + {showArrow && } + {(variant === "gradient-border" || variant === "gradient-fill") && ( + + )} + + ); +} diff --git a/components/shared/CardShared.tsx b/components/shared/CardShared.tsx new file mode 100644 index 0000000..4d60e0f --- /dev/null +++ b/components/shared/CardShared.tsx @@ -0,0 +1,51 @@ +import { ArrowIcon } from "@/components/shared/icons/ArrowIcon"; + +interface CardHeadingProps { + title: string; + subtitle?: string; + titleClassName?: string; + subtitleClassName?: string; + wrapperClassName?: string; +} + +export function CardHeading({ + title, + subtitle, + titleClassName = "", + subtitleClassName = "", + wrapperClassName = "", +}: CardHeadingProps) { + return ( +
+ {subtitle && ( +
+ {subtitle} +
+ )} +

+ {title} +

+
+ ); +} + +export function IconButton({ className = "" }: { className?: string }) { + return ( +
+
+ +
+
+ ); +} diff --git a/components/shared/Counter.tsx b/components/shared/Counter.tsx new file mode 100644 index 0000000..672c52f --- /dev/null +++ b/components/shared/Counter.tsx @@ -0,0 +1,79 @@ +"use client"; + +import { useEffect, useRef, useState } from "react"; + +interface CounterProps { + target: number; + suffix?: string; + prefix?: string; + duration?: number; + className?: string; + title?: string; + numberClassName?: string; + titleClassName?: string; + layout?: "default" | "row-reverse"; + gap?: string; + style?: React.CSSProperties; +} + +export function Counter({ + target, + suffix = "", + prefix = "", + duration = 2000, + className = "", + title, + numberClassName = "", + titleClassName = "", + layout = "default", + gap = "0px", + style, +}: CounterProps) { + const [count, setCount] = useState(0); + const [hasAnimated, setHasAnimated] = useState(false); + const ref = useRef(null); + + useEffect(() => { + const el = ref.current; + if (!el) return; + + const observer = new IntersectionObserver( + ([entry]) => { + if (entry.isIntersecting && !hasAnimated) { + setHasAnimated(true); + const startTime = performance.now(); + const animate = (now: number) => { + const elapsed = now - startTime; + const progress = Math.min(elapsed / duration, 1); + // ease-out + const eased = 1 - Math.pow(1 - progress, 3); + setCount(Math.floor(eased * target)); + if (progress < 1) requestAnimationFrame(animate); + }; + requestAnimationFrame(animate); + } + }, + { threshold: 0.3 } + ); + + observer.observe(el); + return () => observer.disconnect(); + }, [target, duration, hasAnimated]); + + return ( +
+
+ {prefix && {prefix}} + {count} + {suffix && {suffix}} +
+ {title && ( +
{title}
+ )} +
+ ); +} diff --git a/components/shared/IconBox.tsx b/components/shared/IconBox.tsx new file mode 100644 index 0000000..c9164d9 --- /dev/null +++ b/components/shared/IconBox.tsx @@ -0,0 +1,39 @@ +import { ReactNode } from "react"; + +interface IconBoxProps { + icon: ReactNode; + title: string; + description: string; + hasBorder?: boolean; +} + +export function IconBox({ icon, title, description, hasBorder = true }: IconBoxProps) { + return ( +
+
+ {icon} +
+ +
+
+ {title} +
+

+ {description} +

+
+
+ ); +} diff --git a/components/shared/icons/ArrowIcon.tsx b/components/shared/icons/ArrowIcon.tsx new file mode 100644 index 0000000..88394fe --- /dev/null +++ b/components/shared/icons/ArrowIcon.tsx @@ -0,0 +1,20 @@ +export function ArrowIcon({ className = "" }: { className?: string }) { + return ( + + + + ); +} diff --git a/components/shared/icons/ChartIcon.tsx b/components/shared/icons/ChartIcon.tsx new file mode 100644 index 0000000..74e4958 --- /dev/null +++ b/components/shared/icons/ChartIcon.tsx @@ -0,0 +1,193 @@ +export function ChartIcon({ className = "" }: { className?: string }) { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/components/shared/icons/PossibilityIcons.tsx b/components/shared/icons/PossibilityIcons.tsx new file mode 100644 index 0000000..3cb8273 --- /dev/null +++ b/components/shared/icons/PossibilityIcons.tsx @@ -0,0 +1,81 @@ +export function OrbitIcon({ className = "" }: { className?: string }) { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} + +export function FanIcon({ className = "" }: { className?: string }) { + return ( + + + + + + + + + + + ); +} + +export function CirclesIcon({ className = "" }: { className?: string }) { + return ( + + + + + + + + + + + + + + + ); +} + +export function ExpandIcon({ className = "" }: { className?: string }) { + return ( + + + + + + + + + ); +} diff --git a/components/shared/icons/SearchIcon.tsx b/components/shared/icons/SearchIcon.tsx new file mode 100644 index 0000000..cf619d4 --- /dev/null +++ b/components/shared/icons/SearchIcon.tsx @@ -0,0 +1,26 @@ +export function SearchIcon({ className = "" }: { className?: string }) { + return ( + + + + + ); +} diff --git a/data/navigation.ts b/data/navigation.ts new file mode 100644 index 0000000..29dbb97 --- /dev/null +++ b/data/navigation.ts @@ -0,0 +1,70 @@ +export interface NavItem { + label: string; + href: string; + children?: NavItem[]; +} + +export const navigationData: NavItem[] = [ + { + label: "Home", + href: "#", + children: [ + { label: "Home 1", href: "#" }, + { label: "Home 2", href: "#" }, + { label: "Home 3", href: "#" }, + { label: "Home 4", href: "#" }, + { label: "Home 5", href: "#" }, + { label: "Home 6", href: "#" }, + { label: "Home 7", href: "#" }, + { label: "Home 8", href: "#" }, + { label: "Home 9", href: "#" }, + ], + }, + { + label: "Pages", + href: "#", + children: [ + { label: "About Us", href: "#" }, + { label: "About Us 2", href: "#" }, + { label: "Team", href: "#" }, + { label: "Gallery Grid", href: "#" }, + { label: "Gallery Masonry", href: "#" }, + { label: "Pricing plans", href: "#" }, + { label: "FAQ", href: "#" }, + { label: "Typography", href: "#" }, + { label: "404", href: "#" }, + ], + }, + { + label: "Services", + href: "#", + children: [ + { label: "Services Page", href: "#" }, + { label: "Service Single", href: "#" }, + ], + }, + { + label: "Shop", + href: "#", + children: [ + { label: "Products", href: "#" }, + { label: "Single Product", href: "#" }, + { label: "Shopping cart", href: "#" }, + { label: "Checkout", href: "#" }, + { label: "My account", href: "#" }, + ], + }, + { + label: "Blog", + href: "#", + children: [ + { label: "Blog Classic", href: "#" }, + { label: "Blog Grid", href: "#" }, + { label: "Blog Single", href: "#" }, + ], + }, + { + label: "Contacts", + href: "#", + }, +]; diff --git a/eslint.config.mjs b/eslint.config.mjs index 05e726d..29a8892 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,18 +1,19 @@ -import { defineConfig, globalIgnores } from "eslint/config"; -import nextVitals from "eslint-config-next/core-web-vitals"; -import nextTs from "eslint-config-next/typescript"; +import { FlatCompat } from "@eslint/eslintrc"; +import { dirname } from "path"; +import { fileURLToPath } from "url"; -const eslintConfig = defineConfig([ - ...nextVitals, - ...nextTs, - // Override default ignores of eslint-config-next. - globalIgnores([ - // Default ignores of eslint-config-next: - ".next/**", - "out/**", - "build/**", - "next-env.d.ts", - ]), -]); +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const compat = new FlatCompat({ + baseDirectory: __dirname, +}); + +const eslintConfig = [ + ...compat.extends("next/core-web-vitals", "next/typescript"), + { + ignores: [".next/**", "out/**", "build/**", "next-env.d.ts"], + }, +]; export default eslintConfig; diff --git a/public/file.svg b/public/file.svg deleted file mode 100644 index 004145c..0000000 --- a/public/file.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/globe.svg b/public/globe.svg deleted file mode 100644 index 567f17b..0000000 --- a/public/globe.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/images/aiero/3d-woman-shape-glowing-with-bright-holographic-colors-1-min.png b/public/images/aiero/3d-woman-shape-glowing-with-bright-holographic-colors-1-min.png new file mode 100644 index 0000000..a172ffb Binary files /dev/null and b/public/images/aiero/3d-woman-shape-glowing-with-bright-holographic-colors-1-min.png differ diff --git a/public/images/aiero/Dots.png b/public/images/aiero/Dots.png new file mode 100644 index 0000000..d064adb Binary files /dev/null and b/public/images/aiero/Dots.png differ diff --git a/public/images/aiero/Layer_2-min.jpg b/public/images/aiero/Layer_2-min.jpg new file mode 100644 index 0000000..b66afdb Binary files /dev/null and b/public/images/aiero/Layer_2-min.jpg differ diff --git a/public/images/aiero/assistant-artificial-intelligence-min.png b/public/images/aiero/assistant-artificial-intelligence-min.png new file mode 100644 index 0000000..1724f91 Binary files /dev/null and b/public/images/aiero/assistant-artificial-intelligence-min.png differ diff --git a/public/images/aiero/c0eb2845-min.png b/public/images/aiero/c0eb2845-min.png new file mode 100644 index 0000000..cfe73e1 Binary files /dev/null and b/public/images/aiero/c0eb2845-min.png differ diff --git a/public/images/aiero/home-9-img.png b/public/images/aiero/home-9-img.png new file mode 100644 index 0000000..d0dde82 Binary files /dev/null and b/public/images/aiero/home-9-img.png differ diff --git a/public/images/aiero/home-9-top-bg-min.jpg b/public/images/aiero/home-9-top-bg-min.jpg new file mode 100644 index 0000000..840adfb Binary files /dev/null and b/public/images/aiero/home-9-top-bg-min.jpg differ diff --git a/public/images/aiero/logo-dark.png b/public/images/aiero/logo-dark.png new file mode 100644 index 0000000..1771367 Binary files /dev/null and b/public/images/aiero/logo-dark.png differ diff --git a/public/next.svg b/public/next.svg deleted file mode 100644 index 5174b28..0000000 --- a/public/next.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/vercel.svg b/public/vercel.svg deleted file mode 100644 index 7705396..0000000 --- a/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/window.svg b/public/window.svg deleted file mode 100644 index b2b2a44..0000000 --- a/public/window.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 3a13f90..2627c60 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,11 @@ { "compilerOptions": { "target": "ES2017", - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -11,7 +15,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "react-jsx", + "jsx": "preserve", "incremental": true, "plugins": [ { @@ -19,7 +23,9 @@ } ], "paths": { - "@/*": ["./*"] + "@/*": [ + "./*" + ] } }, "include": [ @@ -30,5 +36,7 @@ ".next/dev/types/**/*.ts", "**/*.mts" ], - "exclude": ["node_modules"] + "exclude": [ + "node_modules" + ] }