Animation & Responsive are updated
This commit is contained in:
parent
ce24e8e7fc
commit
3f53ee1ebd
@ -1,8 +1,7 @@
|
|||||||
import Link from "next/link";
|
|
||||||
import Image from "next/image";
|
|
||||||
import Header from "@/components/Header";
|
import Header from "@/components/Header";
|
||||||
import Footer from "@/components/Footer";
|
import Footer from "@/components/Footer";
|
||||||
import InnerBanner from "@/components/InnerBanner";
|
import InnerBanner from "@/components/InnerBanner";
|
||||||
|
import ProjectsContent from "@/components/ProjectsContent";
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
@ -11,17 +10,6 @@ export const metadata: Metadata = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function ProjectsPage() {
|
export default function ProjectsPage() {
|
||||||
const categories = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
title: "Residential Real Estate",
|
|
||||||
description: "Discover our premium residential properties featuring modern architecture, luxury amenities, and prime locations. From spacious apartments to exclusive villas, find your dream home with world-class facilities and exceptional living experiences.",
|
|
||||||
image: "/assets/images/projects/residential-real-estate.jpg",
|
|
||||||
href: "/residential-real-estate",
|
|
||||||
properties: "Residential Real Estate"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-50 dark:bg-black">
|
<div className="min-h-screen bg-gray-50 dark:bg-black">
|
||||||
<Header />
|
<Header />
|
||||||
@ -35,63 +23,7 @@ export default function ProjectsPage() {
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="max-w-7xl mx-auto px-6 py-24">
|
<ProjectsContent />
|
||||||
<div className="text-center mb-12">
|
|
||||||
<h2 className="text-3xl md:text-4xl font-bold text-foreground mb-4">
|
|
||||||
Project Categories
|
|
||||||
</h2>
|
|
||||||
<p className="text-lg text-gray-600 dark:text-gray-400">
|
|
||||||
Browse through our carefully curated collection of properties
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="space-y-8">
|
|
||||||
{categories.map((category) => (
|
|
||||||
<div
|
|
||||||
key={category.id}
|
|
||||||
className="group bg-white dark:bg-gray-900 rounded-2xl overflow-hidden border border-gray-200 dark:border-gray-800 hover:border-primary dark:hover:border-primary shadow-lg hover:shadow-2xl transition-all duration-300"
|
|
||||||
>
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-12 gap-0">
|
|
||||||
{/* Image Section - Left */}
|
|
||||||
<div className="md:col-span-5 relative h-64 md:h-96 overflow-hidden">
|
|
||||||
<Image
|
|
||||||
src={category.image}
|
|
||||||
alt={category.title}
|
|
||||||
fill
|
|
||||||
className="object-cover group-hover:scale-110 transition-transform duration-500"
|
|
||||||
/>
|
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent md:bg-gradient-to-r md:from-transparent md:to-black/10" />
|
|
||||||
|
|
||||||
{/* Badge */}
|
|
||||||
<div className="absolute top-4 left-4 bg-primary text-white px-4 py-2 rounded-full text-sm font-semibold shadow-lg">
|
|
||||||
{category.properties}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Content Section - Right */}
|
|
||||||
<div className="md:col-span-7 p-6 md:p-10 lg:p-12 flex flex-col justify-center">
|
|
||||||
<h3 className="text-2xl md:text-3xl lg:text-4xl font-bold text-foreground mb-4 group-hover:text-primary transition-colors">
|
|
||||||
{category.title}
|
|
||||||
</h3>
|
|
||||||
<p className="text-gray-600 dark:text-gray-400 text-sm md:text-base lg:text-lg mb-8 leading-relaxed">
|
|
||||||
{category.description}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<Link
|
|
||||||
href={category.href}
|
|
||||||
className="inline-flex items-center gap-2 px-8 py-4 bg-gradient-to-r from-primary to-blue-600 text-white rounded-xl font-semibold hover:shadow-xl transition-all duration-300 transform hover:scale-105 w-fit"
|
|
||||||
>
|
|
||||||
View More
|
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
|
|
||||||
</svg>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -34,7 +34,13 @@ export default function About() {
|
|||||||
<div className="max-w-7xl mx-auto px-6 relative z-10">
|
<div className="max-w-7xl mx-auto px-6 relative z-10">
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-center">
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-center">
|
||||||
{/* Text Content */}
|
{/* Text Content */}
|
||||||
<div className="space-y-8 z-10">
|
<motion.div
|
||||||
|
className="space-y-8 z-10"
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true, margin: "-100px" }}
|
||||||
|
transition={{ duration: 0.7 }}
|
||||||
|
>
|
||||||
<h2 className="text-4xl font-bold tracking-tight text-foreground">
|
<h2 className="text-4xl font-bold tracking-tight text-foreground">
|
||||||
Where the Sky Meets <br />
|
Where the Sky Meets <br />
|
||||||
<span className="text-accent dark:text-accent">The Soil.</span>
|
<span className="text-accent dark:text-accent">The Soil.</span>
|
||||||
@ -42,7 +48,9 @@ export default function About() {
|
|||||||
|
|
||||||
<div className="space-y-6 text-lg text-gray-600 dark:text-gray-400 leading-relaxed">
|
<div className="space-y-6 text-lg text-gray-600 dark:text-gray-400 leading-relaxed">
|
||||||
<p>
|
<p>
|
||||||
At Sky and Soil, we curate exceptional living spaces that harmonize with nature. As authorized sales partners for Godrej Properties, we bring you the finest homes in Bangalore's most sought-after locations.
|
At Sky and Soil, we curate exceptional living spaces that harmonize with nat
|
||||||
|
|
||||||
|
ure. As authorized sales partners for Godrej Properties, we bring you the finest homes in Bangalore's most sought-after locations.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Our mission is to connect you with homes that offer not just a roof over your head, but a lifestyle grounded in luxury and elevated by nature. From North Bengaluru to Sarjapur, discover a life of abundance.
|
Our mission is to connect you with homes that offer not just a roof over your head, but a lifestyle grounded in luxury and elevated by nature. From North Bengaluru to Sarjapur, discover a life of abundance.
|
||||||
@ -55,7 +63,7 @@ export default function About() {
|
|||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M13.5 4.5L21 12m0 0l-7.5 7.5M21 12H3" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M13.5 4.5L21 12m0 0l-7.5 7.5M21 12H3" />
|
||||||
</svg>
|
</svg>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Parallax Image Container */}
|
{/* Parallax Image Container */}
|
||||||
<div
|
<div
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import Image from "next/image";
|
|||||||
import { useState, ChangeEvent, FormEvent, useEffect } from "react";
|
import { useState, ChangeEvent, FormEvent, useEffect } from "react";
|
||||||
import ReCAPTCHA from "react-google-recaptcha";
|
import ReCAPTCHA from "react-google-recaptcha";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
|
||||||
interface FormData {
|
interface FormData {
|
||||||
name: string;
|
name: string;
|
||||||
@ -118,7 +119,13 @@ export default function ContactCTA() {
|
|||||||
<section id="contact" className="relative py-24 bg-[#f3f1e6] dark:bg-gray-900">
|
<section id="contact" className="relative py-24 bg-[#f3f1e6] dark:bg-gray-900">
|
||||||
|
|
||||||
<div className="relative z-10 max-w-6xl mx-auto px-6">
|
<div className="relative z-10 max-w-6xl mx-auto px-6">
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-3xl shadow-2xl overflow-hidden border border-gray-100 dark:border-gray-700 flex flex-col md:flex-row">
|
<motion.div
|
||||||
|
className="bg-white dark:bg-gray-800 rounded-3xl shadow-2xl overflow-hidden border border-gray-100 dark:border-gray-700 flex flex-col md:flex-row"
|
||||||
|
initial={{ opacity: 0, y: 40 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true, margin: "-100px" }}
|
||||||
|
transition={{ duration: 0.7 }}
|
||||||
|
>
|
||||||
|
|
||||||
{/* Left Side - Form */}
|
{/* Left Side - Form */}
|
||||||
<div className="w-full md:w-1/2 p-8 md:p-12">
|
<div className="w-full md:w-1/2 p-8 md:p-12">
|
||||||
@ -242,7 +249,7 @@ export default function ContactCTA() {
|
|||||||
/>
|
/>
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent md:bg-gradient-to-l" />
|
<div className="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent md:bg-gradient-to-l" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
|
||||||
const faqs = [
|
const faqs = [
|
||||||
@ -215,7 +216,13 @@ export default function FAQ() {
|
|||||||
|
|
||||||
{/* Right Column: FAQ Content */}
|
{/* Right Column: FAQ Content */}
|
||||||
<div>
|
<div>
|
||||||
<div className="mb-8">
|
<motion.div
|
||||||
|
className="mb-8"
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true, margin: "-100px" }}
|
||||||
|
transition={{ duration: 0.6 }}
|
||||||
|
>
|
||||||
<h2 className="text-3xl md:text-4xl font-bold tracking-tight text-foreground mb-4">
|
<h2 className="text-3xl md:text-4xl font-bold tracking-tight text-foreground mb-4">
|
||||||
Frequently Asked Questions
|
Frequently Asked Questions
|
||||||
</h2>
|
</h2>
|
||||||
@ -241,7 +248,7 @@ export default function FAQ() {
|
|||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{filteredFaqs.map((faq, index) => (
|
{filteredFaqs.map((faq, index) => (
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
|
||||||
export default function Hero() {
|
export default function Hero() {
|
||||||
return (
|
return (
|
||||||
@ -24,8 +27,13 @@ export default function Hero() {
|
|||||||
{/* Location Pins (Decorative) */}
|
{/* Location Pins (Decorative) */}
|
||||||
<div className="absolute inset-0 z-10 pointer-events-none hidden md:block">
|
<div className="absolute inset-0 z-10 pointer-events-none hidden md:block">
|
||||||
{/* Pin 1: Hebbal */}
|
{/* Pin 1: Hebbal */}
|
||||||
<div className="absolute top-[30%] left-[20%] animate-bounce" style={{ animationDuration: '3s' }}>
|
<motion.div
|
||||||
<div className="flex flex-col items-center">
|
className="absolute top-[30%] left-[20%]"
|
||||||
|
initial={{ opacity: 0, y: -20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.8, delay: 1.2 }}
|
||||||
|
>
|
||||||
|
<div className="flex flex-col items-center animate-bounce" style={{ animationDuration: '3s' }}>
|
||||||
<div className="bg-white/90 backdrop-blur-md px-3 py-1 rounded-lg shadow-lg mb-2">
|
<div className="bg-white/90 backdrop-blur-md px-3 py-1 rounded-lg shadow-lg mb-2">
|
||||||
<span className="text-xs font-bold text-black">Hebbal</span>
|
<span className="text-xs font-bold text-black">Hebbal</span>
|
||||||
</div>
|
</div>
|
||||||
@ -34,11 +42,16 @@ export default function Hero() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="h-16 w-0.5 bg-gradient-to-b from-white/50 to-transparent"></div>
|
<div className="h-16 w-0.5 bg-gradient-to-b from-white/50 to-transparent"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Pin 2: Airport */}
|
{/* Pin 2: Airport */}
|
||||||
<div className="absolute top-[20%] right-[25%] animate-bounce" style={{ animationDuration: '4s', animationDelay: '1s' }}>
|
<motion.div
|
||||||
<div className="flex flex-col items-center">
|
className="absolute top-[20%] right-[25%]"
|
||||||
|
initial={{ opacity: 0, y: -20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.8, delay: 1.5 }}
|
||||||
|
>
|
||||||
|
<div className="flex flex-col items-center animate-bounce" style={{ animationDuration: '4s', animationDelay: '1s' }}>
|
||||||
<div className="bg-white/90 backdrop-blur-md px-3 py-1 rounded-lg shadow-lg mb-2">
|
<div className="bg-white/90 backdrop-blur-md px-3 py-1 rounded-lg shadow-lg mb-2">
|
||||||
<span className="text-xs font-bold text-black">Airport</span>
|
<span className="text-xs font-bold text-black">Airport</span>
|
||||||
</div>
|
</div>
|
||||||
@ -47,11 +60,16 @@ export default function Hero() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="h-24 w-0.5 bg-gradient-to-b from-white/50 to-transparent"></div>
|
<div className="h-24 w-0.5 bg-gradient-to-b from-white/50 to-transparent"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Pin 3: Whitefield */}
|
{/* Pin 3: Whitefield */}
|
||||||
<div className="absolute bottom-[30%] right-[15%] animate-bounce" style={{ animationDuration: '3.5s', animationDelay: '0.5s' }}>
|
<motion.div
|
||||||
<div className="flex flex-col items-center">
|
className="absolute bottom-[30%] right-[15%]"
|
||||||
|
initial={{ opacity: 0, y: -20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.8, delay: 1.8 }}
|
||||||
|
>
|
||||||
|
<div className="flex flex-col items-center animate-bounce" style={{ animationDuration: '3.5s', animationDelay: '0.5s' }}>
|
||||||
<div className="bg-white/90 backdrop-blur-md px-3 py-1 rounded-lg shadow-lg mb-2">
|
<div className="bg-white/90 backdrop-blur-md px-3 py-1 rounded-lg shadow-lg mb-2">
|
||||||
<span className="text-xs font-bold text-black">Whitefield</span>
|
<span className="text-xs font-bold text-black">Whitefield</span>
|
||||||
</div>
|
</div>
|
||||||
@ -60,11 +78,16 @@ export default function Hero() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="h-12 w-0.5 bg-gradient-to-b from-white/50 to-transparent"></div>
|
<div className="h-12 w-0.5 bg-gradient-to-b from-white/50 to-transparent"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="relative z-20 max-w-5xl mx-auto px-6 text-center">
|
<motion.div
|
||||||
<h1 className="text-5xl md:text-7xl lg:text-8xl font-bold tracking-tight text-white mb-6 animate-fade-in drop-shadow-lg">
|
className="relative z-20 max-w-5xl mx-auto px-6 text-center"
|
||||||
|
initial={{ opacity: 0, y: 40 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 1, delay: 0.3 }}
|
||||||
|
>
|
||||||
|
<h1 className="text-5xl md:text-7xl lg:text-8xl font-bold tracking-tight text-white mb-6 drop-shadow-lg">
|
||||||
Sky and Soil <br className="hidden md:block" />
|
Sky and Soil <br className="hidden md:block" />
|
||||||
<span className="text-transparent bg-clip-text bg-gradient-to-r from-white to-gray-300">
|
<span className="text-transparent bg-clip-text bg-gradient-to-r from-white to-gray-300">
|
||||||
Bangalore.
|
Bangalore.
|
||||||
@ -76,14 +99,22 @@ export default function Hero() {
|
|||||||
</p> */}
|
</p> */}
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Scroll Indicator */}
|
{/* Scroll Indicator */}
|
||||||
<div className="absolute bottom-10 left-1/2 transform -translate-x-1/2 animate-bounce z-20">
|
<motion.div
|
||||||
|
className="absolute bottom-10 left-1/2 transform -translate-x-1/2 z-20"
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 0.8, y: [0, 10, 0] }}
|
||||||
|
transition={{
|
||||||
|
opacity: { duration: 1, delay: 1.5 },
|
||||||
|
y: { duration: 1.5, repeat: Infinity, ease: "easeInOut" }
|
||||||
|
}}
|
||||||
|
>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6 text-white/80">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6 text-white/80">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</motion.div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useState, useRef, MouseEvent } from "react";
|
import { useState, useRef, MouseEvent } from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
import { FloatingHouse, RotatingKey } from "./PropertyAnimations";
|
import { FloatingHouse, RotatingKey } from "./PropertyAnimations";
|
||||||
|
|
||||||
export default function Lifestyle() {
|
export default function Lifestyle() {
|
||||||
@ -37,11 +37,15 @@ export default function Lifestyle() {
|
|||||||
<div className="max-w-7xl mx-auto px-6 relative z-10">
|
<div className="max-w-7xl mx-auto px-6 relative z-10">
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-center">
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-center">
|
||||||
{/* Image Side with Zoom Effect */}
|
{/* Image Side with Zoom Effect */}
|
||||||
<div
|
<motion.div
|
||||||
className="order-2 lg:order-1 relative h-[600px] rounded-3xl overflow-hidden shadow-2xl group cursor-crosshair"
|
className="order-2 lg:order-1 relative h-[600px] rounded-3xl overflow-hidden shadow-2xl group cursor-crosshair"
|
||||||
ref={imageRef}
|
ref={imageRef}
|
||||||
onMouseMove={handleMouseMove}
|
onMouseMove={handleMouseMove}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
|
initial={{ opacity: 0, scale: 0.95 }}
|
||||||
|
whileInView={{ opacity: 1, scale: 1 }}
|
||||||
|
viewport={{ once: true, margin: "-100px" }}
|
||||||
|
transition={{ duration: 0.7 }}
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
src="/assets/images/home/experience.webp"
|
src="/assets/images/home/experience.webp"
|
||||||
@ -59,10 +63,16 @@ export default function Lifestyle() {
|
|||||||
Clubhouse & Amenities
|
Clubhouse & Amenities
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Content Side */}
|
{/* Content Side */}
|
||||||
<div className="order-1 lg:order-2 space-y-8">
|
<motion.div
|
||||||
|
className="order-1 lg:order-2 space-y-8"
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true, margin: "-100px" }}
|
||||||
|
transition={{ duration: 0.7, delay: 0.2 }}
|
||||||
|
>
|
||||||
<h2 className="text-4xl md:text-5xl font-bold tracking-tight text-foreground">
|
<h2 className="text-4xl md:text-5xl font-bold tracking-tight text-foreground">
|
||||||
Experience the <br />
|
Experience the <br />
|
||||||
<span className="text-primary">Aurora Lifestyle.</span>
|
<span className="text-primary">Aurora Lifestyle.</span>
|
||||||
@ -100,7 +110,7 @@ export default function Lifestyle() {
|
|||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
88
src/components/ProjectsContent.tsx
Normal file
88
src/components/ProjectsContent.tsx
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import Link from "next/link";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
|
||||||
|
const categories = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: "Residential Real Estate",
|
||||||
|
description: "Discover our premium residential properties featuring modern architecture, luxury amenities, and prime locations. From spacious apartments to exclusive villas, find your dream home with world-class facilities and exceptional living experiences.",
|
||||||
|
image: "/assets/images/projects/residential-real-estate.jpg",
|
||||||
|
href: "/residential-real-estate",
|
||||||
|
properties: "Residential Real Estate"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function ProjectsContent() {
|
||||||
|
return (
|
||||||
|
<div className="max-w-7xl mx-auto px-6 py-24">
|
||||||
|
<motion.div
|
||||||
|
className="text-center mb-12"
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true, margin: "-100px" }}
|
||||||
|
transition={{ duration: 0.6 }}
|
||||||
|
>
|
||||||
|
<h2 className="text-3xl md:text-4xl font-bold text-foreground mb-4">
|
||||||
|
Project Categories
|
||||||
|
</h2>
|
||||||
|
<p className="text-lg text-gray-600 dark:text-gray-400">
|
||||||
|
Browse through our carefully curated collection of properties
|
||||||
|
</p>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<div className="space-y-8">
|
||||||
|
{categories.map((category, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={category.id}
|
||||||
|
className="group bg-white dark:bg-gray-900 rounded-2xl overflow-hidden border border-gray-200 dark:border-gray-800 hover:border-primary dark:hover:border-primary shadow-lg hover:shadow-2xl transition-all duration-300"
|
||||||
|
initial={{ opacity: 0, y: 40 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true, margin: "-100px" }}
|
||||||
|
transition={{ duration: 0.7, delay: index * 0.1 }}
|
||||||
|
>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-12 gap-0">
|
||||||
|
{/* Image Section - Left */}
|
||||||
|
<div className="md:col-span-5 relative h-64 md:h-96 overflow-hidden">
|
||||||
|
<Image
|
||||||
|
src={category.image}
|
||||||
|
alt={category.title}
|
||||||
|
fill
|
||||||
|
className="object-cover group-hover:scale-110 transition-transform duration-500"
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent md:bg-gradient-to-r md:from-transparent md:to-black/10" />
|
||||||
|
|
||||||
|
{/* Badge */}
|
||||||
|
<div className="absolute top-4 left-4 bg-primary text-white px-4 py-2 rounded-full text-sm font-semibold shadow-lg">
|
||||||
|
{category.properties}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Content Section - Right */}
|
||||||
|
<div className="md:col-span-7 p-6 md:p-10 lg:p-12 flex flex-col justify-center">
|
||||||
|
<h3 className="text-2xl md:text-3xl lg:text-4xl font-bold text-foreground mb-4 group-hover:text-primary transition-colors">
|
||||||
|
{category.title}
|
||||||
|
</h3>
|
||||||
|
<p className="text-gray-600 dark:text-gray-400 text-sm md:text-base lg:text-lg mb-8 leading-relaxed">
|
||||||
|
{category.description}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
href={category.href}
|
||||||
|
className="inline-flex items-center gap-2 px-8 py-4 bg-gradient-to-r from-primary to-blue-600 text-white rounded-xl font-semibold hover:shadow-xl transition-all duration-300 transform hover:scale-105 w-fit"
|
||||||
|
>
|
||||||
|
View More
|
||||||
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
|
||||||
|
</svg>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -3,6 +3,7 @@
|
|||||||
import { useState, useRef } from "react";
|
import { useState, useRef } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { properties } from "@/data/properties";
|
import { properties } from "@/data/properties";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
|
||||||
type Category = "Apartments" | "Premium Homes" | "Luxury";
|
type Category = "Apartments" | "Premium Homes" | "Luxury";
|
||||||
|
|
||||||
@ -29,14 +30,20 @@ export default function Properties({ layout = "slider" }: PropertiesProps) {
|
|||||||
return (
|
return (
|
||||||
<section id="projects" className="py-24 bg-white dark:bg-black overflow-hidden">
|
<section id="projects" className="py-24 bg-white dark:bg-black overflow-hidden">
|
||||||
<div className="max-w-7xl mx-auto px-6">
|
<div className="max-w-7xl mx-auto px-6">
|
||||||
<div className="text-center mb-12">
|
<motion.div
|
||||||
|
className="text-center mb-12"
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true, margin: "-100px" }}
|
||||||
|
transition={{ duration: 0.6 }}
|
||||||
|
>
|
||||||
<h2 className="text-3xl md:text-4xl font-bold tracking-tight text-foreground mb-4">
|
<h2 className="text-3xl md:text-4xl font-bold tracking-tight text-foreground mb-4">
|
||||||
Our Signature Projects
|
Our Signature Projects
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-lg text-gray-600 dark:text-gray-400">
|
<p className="text-lg text-gray-600 dark:text-gray-400">
|
||||||
Discover a home that complements your lifestyle.
|
Discover a home that complements your lifestyle.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Tabs */}
|
{/* Tabs */}
|
||||||
<div className="flex justify-center mb-12">
|
<div className="flex justify-center mb-12">
|
||||||
@ -92,12 +99,16 @@ export default function Properties({ layout = "slider" }: PropertiesProps) {
|
|||||||
if (activeTab !== "All" && index > 0) return null;
|
if (activeTab !== "All" && index > 0) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<motion.div
|
||||||
key={property.id}
|
key={property.id}
|
||||||
className={activeTab === "All"
|
className={activeTab === "All"
|
||||||
? "flex-shrink-0 snap-center w-full md:w-[calc(50%-12px)] lg:w-[calc(33.333%-16px)]"
|
? "flex-shrink-0 snap-center w-full md:w-[calc(50%-12px)] lg:w-[calc(33.333%-16px)]"
|
||||||
: "flex-shrink-0 w-full max-w-md mx-auto snap-center"
|
: "flex-shrink-0 w-full max-w-md mx-auto snap-center"
|
||||||
}
|
}
|
||||||
|
initial={{ opacity: 0, y: 40 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
|
transition={{ duration: 0.6, delay: index * 0.15 }}
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
href={`/residential-real-estate/${property.slug}`}
|
href={`/residential-real-estate/${property.slug}`}
|
||||||
@ -144,7 +155,7 @@ export default function Properties({ layout = "slider" }: PropertiesProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import InnerBanner from "@/components/InnerBanner";
|
|||||||
import PropertyFilters, { FilterState } from "@/components/PropertyFilters";
|
import PropertyFilters, { FilterState } from "@/components/PropertyFilters";
|
||||||
import PropertyCard from "@/components/PropertyCard";
|
import PropertyCard from "@/components/PropertyCard";
|
||||||
import { properties } from "@/data/properties";
|
import { properties } from "@/data/properties";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
|
||||||
export default function PropertiesClient() {
|
export default function PropertiesClient() {
|
||||||
const [filteredProperties, setFilteredProperties] = useState(properties);
|
const [filteredProperties, setFilteredProperties] = useState(properties);
|
||||||
@ -79,15 +80,30 @@ export default function PropertiesClient() {
|
|||||||
<PropertyFilters onFilterChange={handleFilterChange} />
|
<PropertyFilters onFilterChange={handleFilterChange} />
|
||||||
|
|
||||||
<div className="max-w-7xl mx-auto px-6 py-12">
|
<div className="max-w-7xl mx-auto px-6 py-12">
|
||||||
<h2 className="text-3xl font-bold text-foreground mb-8">Browse Our Properties</h2>
|
<motion.h2
|
||||||
|
className="text-3xl font-bold text-foreground mb-8"
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.5 }}
|
||||||
|
>
|
||||||
|
Browse Our Properties
|
||||||
|
</motion.h2>
|
||||||
|
|
||||||
{/* Property Grid */}
|
{/* Property Grid */}
|
||||||
{filteredProperties.length > 0 ? (
|
{filteredProperties.length > 0 ? (
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
{filteredProperties.map((property) => (
|
{filteredProperties.map((property, index) => (
|
||||||
<PropertyCard key={property.id} property={property} />
|
<motion.div
|
||||||
))}
|
key={property.id}
|
||||||
</div>
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
|
transition={{ duration: 0.5, delay: index * 0.1 }}
|
||||||
|
>
|
||||||
|
<PropertyCard property={property} />
|
||||||
|
</motion.div>
|
||||||
|
))} </div>
|
||||||
) : (
|
) : (
|
||||||
<div className="text-center py-20">
|
<div className="text-center py-20">
|
||||||
<svg className="w-20 h-20 mx-auto text-gray-400 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-20 h-20 mx-auto text-gray-400 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
import { GrowingBuilding } from "./PropertyAnimations";
|
import { GrowingBuilding } from "./PropertyAnimations";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
|
||||||
export default function Testimonials() {
|
export default function Testimonials() {
|
||||||
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||||
@ -81,7 +82,13 @@ export default function Testimonials() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="max-w-7xl mx-auto px-6 relative z-10">
|
<div className="max-w-7xl mx-auto px-6 relative z-10">
|
||||||
<div className="text-center mb-16">
|
<motion.div
|
||||||
|
className="text-center mb-16"
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true, margin: "-100px" }}
|
||||||
|
transition={{ duration: 0.6 }}
|
||||||
|
>
|
||||||
<h2 className="text-3xl md:text-4xl font-bold tracking-tight text-foreground mb-4">
|
<h2 className="text-3xl md:text-4xl font-bold tracking-tight text-foreground mb-4">
|
||||||
Stories of Satisfaction
|
Stories of Satisfaction
|
||||||
</h2>
|
</h2>
|
||||||
@ -92,7 +99,7 @@ export default function Testimonials() {
|
|||||||
<span className="text-lg font-semibold text-foreground">5.0</span>
|
<span className="text-lg font-semibold text-foreground">5.0</span>
|
||||||
<span className="text-gray-500">• Based on {testimonials.length} reviews</span>
|
<span className="text-gray-500">• Based on {testimonials.length} reviews</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Slider Container */}
|
{/* Slider Container */}
|
||||||
<div className="relative group">
|
<div className="relative group">
|
||||||
|
|||||||
@ -1,13 +1,10 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useEffect, useRef } from "react";
|
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { FloatingHouse, RotatingKey, GrowingBuilding } from "./PropertyAnimations";
|
import { FloatingHouse, RotatingKey, GrowingBuilding } from "./PropertyAnimations";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
|
||||||
export default function WhyChooseUs() {
|
export default function WhyChooseUs() {
|
||||||
const [visibleCards, setVisibleCards] = useState<boolean[]>([false, false, false, false]);
|
|
||||||
const sectionRef = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
const features = [
|
const features = [
|
||||||
{
|
{
|
||||||
title: "Prime Locations",
|
title: "Prime Locations",
|
||||||
@ -31,40 +28,8 @@ export default function WhyChooseUs() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const observer = new IntersectionObserver(
|
|
||||||
(entries) => {
|
|
||||||
entries.forEach((entry) => {
|
|
||||||
if (entry.isIntersecting) {
|
|
||||||
// Trigger cards to appear one by one with delay
|
|
||||||
features.forEach((_, index) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
setVisibleCards((prev) => {
|
|
||||||
const newVisible = [...prev];
|
|
||||||
newVisible[index] = true;
|
|
||||||
return newVisible;
|
|
||||||
});
|
|
||||||
}, index * 150); // 150ms delay between each card
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
{ threshold: 0.2 }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (sectionRef.current) {
|
|
||||||
observer.observe(sectionRef.current);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (sectionRef.current) {
|
|
||||||
observer.unobserve(sectionRef.current);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section ref={sectionRef} className="py-24 bg-secondary dark:bg-gray-900/50 relative overflow-hidden">
|
<section className="py-24 bg-secondary dark:bg-gray-900/50 relative overflow-hidden">
|
||||||
|
|
||||||
{/* Decorative Animations */}
|
{/* Decorative Animations */}
|
||||||
<div className="absolute top-20 left-10 opacity-50 hidden lg:block">
|
<div className="absolute top-20 left-10 opacity-50 hidden lg:block">
|
||||||
@ -78,26 +43,31 @@ export default function WhyChooseUs() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="max-w-7xl mx-auto px-6 relative z-10">
|
<div className="max-w-7xl mx-auto px-6 relative z-10">
|
||||||
<div className="text-center mb-16">
|
<motion.div
|
||||||
<h2 className="text-3xl md:text-4xl font-bold tracking-tight text-foreground mb-4 animate-fade-in">
|
className="text-center mb-16"
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true, margin: "-100px" }}
|
||||||
|
transition={{ duration: 0.6 }}
|
||||||
|
>
|
||||||
|
<h2 className="text-3xl md:text-4xl font-bold tracking-tight text-foreground mb-4">
|
||||||
Why Sky and Soil?
|
Why Sky and Soil?
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-lg text-gray-600 dark:text-gray-400 max-w-2xl mx-auto animate-slide-up">
|
<p className="text-lg text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
|
||||||
We bridge the gap between your dreams and reality with premium properties and unmatched service.
|
We bridge the gap between your dreams and reality with premium properties and unmatched service.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
|
||||||
{features.map((feature, index) => (
|
{features.map((feature, index) => (
|
||||||
<div
|
<motion.div
|
||||||
key={index}
|
key={index}
|
||||||
className={`bg-white dark:bg-gray-800 p-8 rounded-2xl shadow-sm hover:shadow-xl transition-all duration-500 flex flex-col items-center text-center group transform ${visibleCards[index]
|
className="bg-white dark:bg-gray-800 p-8 rounded-2xl shadow-sm hover:shadow-xl transition-all duration-500 flex flex-col items-center text-center group"
|
||||||
? 'translate-y-0 opacity-100'
|
initial={{ opacity: 0, y: 40 }}
|
||||||
: 'translate-y-10 opacity-0'
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
}`}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
style={{
|
transition={{ duration: 0.5, delay: index * 0.15 }}
|
||||||
transitionDelay: `${index * 100}ms`
|
whileHover={{ y: -10, transition: { duration: 0.3 } }}
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div className="mb-6 p-4 bg-blue-50 dark:bg-blue-900/30 rounded-full group-hover:scale-110 group-hover:rotate-6 transition-all duration-300 relative w-20 h-20 flex items-center justify-center">
|
<div className="mb-6 p-4 bg-blue-50 dark:bg-blue-900/30 rounded-full group-hover:scale-110 group-hover:rotate-6 transition-all duration-300 relative w-20 h-20 flex items-center justify-center">
|
||||||
<div className="relative w-[80%] h-[80%]">
|
<div className="relative w-[80%] h-[80%]">
|
||||||
@ -115,7 +85,7 @@ export default function WhyChooseUs() {
|
|||||||
<p className="text-gray-600 dark:text-gray-400 leading-relaxed">
|
<p className="text-gray-600 dark:text-gray-400 leading-relaxed">
|
||||||
{feature.description}
|
{feature.description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</motion.div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user