Initial commit 🌟
This commit is contained in:
242
src/app/components/Contact/Contact.tsx
Normal file
242
src/app/components/Contact/Contact.tsx
Normal file
@@ -0,0 +1,242 @@
|
||||
// File: src/components/home/ContactSection.tsx
|
||||
|
||||
import {
|
||||
EnvironmentOutlined,
|
||||
MailOutlined,
|
||||
PhoneOutlined,
|
||||
SendOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { Button, Col, Form, Input, message, Row, Typography } from "antd";
|
||||
import { motion } from "framer-motion";
|
||||
import Image from "next/image";
|
||||
import React, { useState } from "react";
|
||||
import styles from "./ContactSection.module.css";
|
||||
|
||||
const { Title, Paragraph, Text } = Typography;
|
||||
const { TextArea } = Input;
|
||||
|
||||
const ContactSection: React.FC = () => {
|
||||
const [form] = Form.useForm();
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
setSubmitting(true);
|
||||
|
||||
// Simulate API call
|
||||
setTimeout(() => {
|
||||
message.success("Your message has been sent successfully!");
|
||||
form.resetFields();
|
||||
setSubmitting(false);
|
||||
}, 1500);
|
||||
};
|
||||
|
||||
const containerVariants = {
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
staggerChildren: 0.2,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const itemVariants = {
|
||||
hidden: { y: 20, opacity: 0 },
|
||||
visible: {
|
||||
y: 0,
|
||||
opacity: 1,
|
||||
transition: { duration: 0.5 },
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<section className={styles.contactSection}>
|
||||
<div className={styles.backgroundElements}>
|
||||
<div className={styles.glowOrbTop}></div>
|
||||
<div className={styles.glowOrbBottom}></div>
|
||||
</div>
|
||||
|
||||
<div className={styles.container}>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
viewport={{ once: true }}
|
||||
className={styles.sectionHeader}
|
||||
>
|
||||
<Title level={2} className={styles.sectionTitle}>
|
||||
Get In Touch
|
||||
</Title>
|
||||
<Paragraph className={styles.sectionSubtitle}>
|
||||
Ready to transform your ideas into reality? Contact us today.
|
||||
</Paragraph>
|
||||
</motion.div>
|
||||
|
||||
<Row gutter={[48, 48]} className={styles.contactContent}>
|
||||
<Col xs={24} lg={10}>
|
||||
<motion.div
|
||||
variants={containerVariants}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={{ once: true }}
|
||||
className={styles.contactInfo}
|
||||
>
|
||||
<motion.div
|
||||
variants={itemVariants}
|
||||
className={styles.contactInfoItem}
|
||||
>
|
||||
<div className={styles.iconWrapper}>
|
||||
<MailOutlined className={styles.contactIcon} />
|
||||
</div>
|
||||
<div>
|
||||
<Text strong className={styles.contactLabel}>
|
||||
Email
|
||||
</Text>
|
||||
<Text className={styles.contactValue}>
|
||||
info@techmaster.com
|
||||
</Text>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
variants={itemVariants}
|
||||
className={styles.contactInfoItem}
|
||||
>
|
||||
<div className={styles.iconWrapper}>
|
||||
<PhoneOutlined className={styles.contactIcon} />
|
||||
</div>
|
||||
<div>
|
||||
<Text strong className={styles.contactLabel}>
|
||||
Phone
|
||||
</Text>
|
||||
<Text className={styles.contactValue}>+1 (555) 123-4567</Text>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
variants={itemVariants}
|
||||
className={styles.contactInfoItem}
|
||||
>
|
||||
<div className={styles.iconWrapper}>
|
||||
<EnvironmentOutlined className={styles.contactIcon} />
|
||||
</div>
|
||||
<div>
|
||||
<Text strong className={styles.contactLabel}>
|
||||
Address
|
||||
</Text>
|
||||
<Text className={styles.contactValue}>
|
||||
1234 Tech Boulevard, Innovation District
|
||||
<br />
|
||||
San Francisco, CA 94105
|
||||
</Text>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
variants={itemVariants}
|
||||
className={styles.mapContainer}
|
||||
>
|
||||
<Image
|
||||
src="/api/placeholder/400/200"
|
||||
alt="Office Location Map"
|
||||
className={styles.mapImage}
|
||||
width={400}
|
||||
height={400}
|
||||
/>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</Col>
|
||||
|
||||
<Col xs={24} lg={14}>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: 30 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.2 }}
|
||||
viewport={{ once: true }}
|
||||
className={styles.contactForm}
|
||||
>
|
||||
<Title level={4} className={styles.formTitle}>
|
||||
Send Us a Message
|
||||
</Title>
|
||||
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
onFinish={handleSubmit}
|
||||
className={styles.form}
|
||||
>
|
||||
<Row gutter={16}>
|
||||
<Col xs={24} sm={12}>
|
||||
<Form.Item
|
||||
name="name"
|
||||
label="Name"
|
||||
rules={[
|
||||
{ required: true, message: "Please enter your name" },
|
||||
]}
|
||||
>
|
||||
<Input size="large" placeholder="Your name" />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col xs={24} sm={12}>
|
||||
<Form.Item
|
||||
name="email"
|
||||
label="Email"
|
||||
rules={[
|
||||
{ required: true, message: "Please enter your email" },
|
||||
{
|
||||
type: "email",
|
||||
message: "Please enter a valid email",
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input size="large" placeholder="Your email" />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Form.Item
|
||||
name="subject"
|
||||
label="Subject"
|
||||
rules={[
|
||||
{ required: true, message: "Please enter a subject" },
|
||||
]}
|
||||
>
|
||||
<Input size="large" placeholder="How can we help you?" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="message"
|
||||
label="Message"
|
||||
rules={[
|
||||
{ required: true, message: "Please enter your message" },
|
||||
]}
|
||||
>
|
||||
<TextArea
|
||||
rows={5}
|
||||
placeholder="Tell us about your project..."
|
||||
className={styles.messageInput}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
size="large"
|
||||
icon={<SendOutlined />}
|
||||
loading={submitting}
|
||||
className={styles.submitButton}
|
||||
>
|
||||
Send Message
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</motion.div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContactSection;
|
||||
187
src/app/components/Contact/ContactSection.module.css
Normal file
187
src/app/components/Contact/ContactSection.module.css
Normal file
@@ -0,0 +1,187 @@
|
||||
/* File: src/components/home/ContactSection.module.css */
|
||||
|
||||
.contactSection {
|
||||
padding: 100px 0;
|
||||
background-color: #f8f9fa;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 16px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.backgroundElements {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.glowOrbTop {
|
||||
position: absolute;
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(24, 144, 255, 0.15) 0%, rgba(24, 144, 255, 0.05) 50%, rgba(0, 0, 0, 0) 70%);
|
||||
top: -200px;
|
||||
left: -150px;
|
||||
filter: blur(50px);
|
||||
}
|
||||
|
||||
.glowOrbBottom {
|
||||
position: absolute;
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(64, 169, 255, 0.15) 0%, rgba(64, 169, 255, 0.05) 50%, rgba(0, 0, 0, 0) 70%);
|
||||
bottom: -250px;
|
||||
right: -200px;
|
||||
filter: blur(60px);
|
||||
}
|
||||
|
||||
.sectionHeader {
|
||||
text-align: center;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
font-size: 2.5rem !important;
|
||||
font-weight: 700 !important;
|
||||
margin-bottom: 16px !important;
|
||||
background: linear-gradient(90deg, #1890ff, #096dd9);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.sectionSubtitle {
|
||||
font-size: 1.1rem;
|
||||
color: #666;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.contactContent {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.05);
|
||||
backdrop-filter: blur(8px);
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
.contactInfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.contactInfoItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.iconWrapper {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #1890ff, #096dd9);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: 0 4px 8px rgba(24, 144, 255, 0.25);
|
||||
}
|
||||
|
||||
.contactIcon {
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.contactLabel {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.contactValue {
|
||||
color: #666;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.mapContainer {
|
||||
margin-top: 16px;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.mapImage {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.contactForm {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 32px;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.formTitle {
|
||||
margin-bottom: 24px !important;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.messageInput {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.submitButton {
|
||||
height: 48px;
|
||||
padding: 0 32px;
|
||||
border-radius: 24px;
|
||||
font-weight: 500;
|
||||
background: linear-gradient(90deg, #1890ff, #096dd9);
|
||||
border: none;
|
||||
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.15);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.submitButton:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(24, 144, 255, 0.2);
|
||||
background: linear-gradient(90deg, #40a9ff, #1890ff);
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.contactContent {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.contactForm {
|
||||
padding: 24px;
|
||||
margin-top: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.contactSection {
|
||||
padding: 60px 0;
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
font-size: 2rem !important;
|
||||
}
|
||||
|
||||
.mapContainer {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
74
src/app/components/Header/Header.module.css
Normal file
74
src/app/components/Header/Header.module.css
Normal file
@@ -0,0 +1,74 @@
|
||||
.header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
box-shadow: 0 2px 20px rgba(0, 0, 0, 0.1);
|
||||
padding: 15px 0;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.headerContainer {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.logoContainer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.logoText {
|
||||
margin: 0 !important;
|
||||
font-weight: 700 !important;
|
||||
font-size: 1.5rem !important;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.logoHighlight {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.navContainer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.menu {
|
||||
border-bottom: none !important;
|
||||
background: transparent !important;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.menu li {
|
||||
padding: 0 15px !important;
|
||||
}
|
||||
|
||||
.ctaContainer {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.ctaButton {
|
||||
/* background: var(--primary) !important; */
|
||||
border: none !important;
|
||||
font-weight: 500 !important;
|
||||
padding: 0 25px !important;
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.navContainer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.headerContainer {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
73
src/app/components/Header/Header.tsx
Normal file
73
src/app/components/Header/Header.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
"use client";
|
||||
|
||||
import { Menu, MenuProps, Typography } from "antd";
|
||||
import { motion } from "framer-motion";
|
||||
import Link from "next/link";
|
||||
import styles from "./Header.module.css";
|
||||
|
||||
const { Title } = Typography;
|
||||
|
||||
const items: MenuProps['items'] = [
|
||||
{
|
||||
label: <Link href="/">Home</Link>,
|
||||
key: 'home',
|
||||
},
|
||||
{
|
||||
label: <Link href="/services">Services</Link>,
|
||||
key: 'services',
|
||||
},
|
||||
{
|
||||
label: <Link href="/projects">Projects</Link>,
|
||||
key: 'projects',
|
||||
},
|
||||
{
|
||||
label: <Link href="/about">About</Link>,
|
||||
key: 'about',
|
||||
},
|
||||
{
|
||||
label: <Link href="/contact">Contact</Link>,
|
||||
key: 'contact',
|
||||
},
|
||||
];
|
||||
|
||||
const Header = () => {
|
||||
return (
|
||||
<header className={styles.header}>
|
||||
<div className={styles.headerContainer}>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
className={styles.logoContainer}
|
||||
>
|
||||
<Link href="/">
|
||||
<Title level={3} className={styles.logoText}>
|
||||
Tech Master
|
||||
</Title>
|
||||
</Link>
|
||||
</motion.div>
|
||||
|
||||
<nav className={styles.navContainer}>
|
||||
<Menu
|
||||
mode="horizontal"
|
||||
items={items}
|
||||
className={styles.menu}
|
||||
/>
|
||||
|
||||
{/* <Space className={styles.ctaContainer}>
|
||||
<Button
|
||||
type="primary"
|
||||
shape="round"
|
||||
size="large"
|
||||
className={styles.ctaButton}
|
||||
>
|
||||
Get Started
|
||||
</Button>
|
||||
</Space> */}
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
109
src/app/components/Hero/HeroSection.module.css
Normal file
109
src/app/components/Hero/HeroSection.module.css
Normal file
@@ -0,0 +1,109 @@
|
||||
.heroSection {
|
||||
position: relative;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(135deg, #0f0525 0%, #2a0b45 100%);
|
||||
text-align: center;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.heroContent {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.badge {
|
||||
background: rgba(110, 72, 170, 0.2);
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 2px;
|
||||
padding: 8px 20px;
|
||||
border-radius: 20px;
|
||||
border: 1px solid rgba(157, 80, 187, 0.5);
|
||||
display: inline-block;
|
||||
margin-bottom: 30px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: white !important;
|
||||
font-size: 3.2rem !important;
|
||||
line-height: 1.3 !important;
|
||||
margin-bottom: 24px !important;
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background: linear-gradient(90deg, #6e48aa, #9d50bb);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.description {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 40px;
|
||||
max-width: 700px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.buttonGroup {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
justify-content: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.portfolioButton {
|
||||
background: linear-gradient(135deg, #6e48aa 0%, #9d50bb 100%) !important;
|
||||
border: none !important;
|
||||
font-weight: 500 !important;
|
||||
height: 50px !important;
|
||||
padding: 0 30px !important;
|
||||
border-radius: 4px !important;
|
||||
}
|
||||
|
||||
.projectButton {
|
||||
background: transparent !important;
|
||||
border: 2px solid #9d50bb !important;
|
||||
color: white !important;
|
||||
height: 50px !important;
|
||||
padding: 0 30px !important;
|
||||
border-radius: 4px !important;
|
||||
transition: all 0.3s ease !important;
|
||||
}
|
||||
|
||||
.projectButton:hover {
|
||||
background: rgba(157, 80, 187, 0.1) !important;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.title {
|
||||
font-size: 2.2rem !important;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.buttonGroup {
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.portfolioButton,
|
||||
.projectButton {
|
||||
width: 100%;
|
||||
max-width: 280px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
60
src/app/components/Hero/HeroSection.tsx
Normal file
60
src/app/components/Hero/HeroSection.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
"use client";
|
||||
|
||||
import { Button, Typography } from "antd";
|
||||
import { motion } from "framer-motion";
|
||||
import styles from "./HeroSection.module.css";
|
||||
import ParticleBackground from "./ParticleBackground";
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
|
||||
const HeroSection = () => {
|
||||
return (
|
||||
<section className={styles.heroSection}>
|
||||
<ParticleBackground />
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className={styles.heroContent}
|
||||
>
|
||||
<div className={styles.badge}>
|
||||
<span>AWARD WINNING IT SOLUTIONS</span>
|
||||
</div>
|
||||
|
||||
<Title className={styles.title}>
|
||||
Pioneering{" "}
|
||||
<span className={styles.highlight}>Digital Transformation</span>
|
||||
<br />
|
||||
From Zero To Hero
|
||||
</Title>
|
||||
|
||||
<Text className={styles.description}>
|
||||
We are an award-winning Dubai based technology agency, focused on
|
||||
creating cutting-edge digital experiences for ambitious businesses and
|
||||
enterprises.
|
||||
</Text>
|
||||
|
||||
<div className={styles.buttonGroup}>
|
||||
<motion.div whileHover={{ scale: 1.05 }}>
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
className={styles.portfolioButton}
|
||||
>
|
||||
VIEW OUR PORTFOLIO
|
||||
</Button>
|
||||
</motion.div>
|
||||
|
||||
<motion.div whileHover={{ scale: 1.05 }}>
|
||||
<Button size="large" className={styles.projectButton}>
|
||||
START A PROJECT
|
||||
</Button>
|
||||
</motion.div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default HeroSection;
|
||||
137
src/app/components/Hero/ParticleBackground.tsx
Normal file
137
src/app/components/Hero/ParticleBackground.tsx
Normal file
@@ -0,0 +1,137 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
particlesJS: any;
|
||||
}
|
||||
}
|
||||
|
||||
const ParticleBackground = () => {
|
||||
useEffect(() => {
|
||||
if (typeof window !== "undefined" && window.particlesJS) {
|
||||
window.particlesJS("particles-js", {
|
||||
particles: {
|
||||
number: {
|
||||
value: 80,
|
||||
density: {
|
||||
enable: true,
|
||||
value_area: 800,
|
||||
},
|
||||
},
|
||||
color: {
|
||||
value: "#ffffff",
|
||||
},
|
||||
shape: {
|
||||
type: "circle",
|
||||
stroke: {
|
||||
width: 0,
|
||||
color: "#000000",
|
||||
},
|
||||
polygon: {
|
||||
nb_sides: 5,
|
||||
},
|
||||
image: {
|
||||
src: "img/github.svg",
|
||||
width: 100,
|
||||
height: 100,
|
||||
},
|
||||
},
|
||||
opacity: {
|
||||
value: 0.4,
|
||||
random: true,
|
||||
anim: {
|
||||
enable: false,
|
||||
speed: 1,
|
||||
opacity_min: 0.1,
|
||||
sync: false,
|
||||
},
|
||||
},
|
||||
size: {
|
||||
value: 7,
|
||||
random: true,
|
||||
anim: {
|
||||
enable: false,
|
||||
speed: 40,
|
||||
size_min: 0.1,
|
||||
sync: false,
|
||||
},
|
||||
},
|
||||
line_linked: {
|
||||
enable: true,
|
||||
distance: 150,
|
||||
color: "#ffffff",
|
||||
opacity: 0.3,
|
||||
width: 1,
|
||||
},
|
||||
move: {
|
||||
enable: true,
|
||||
speed: 2,
|
||||
direction: "none",
|
||||
random: true,
|
||||
straight: false,
|
||||
out_mode: "bounce",
|
||||
bounce: false,
|
||||
attract: {
|
||||
enable: false,
|
||||
rotateX: 600,
|
||||
rotateY: 1200,
|
||||
},
|
||||
},
|
||||
},
|
||||
interactivity: {
|
||||
detect_on: "canvas",
|
||||
events: {
|
||||
onhover: {
|
||||
enable: true,
|
||||
mode: "grab",
|
||||
},
|
||||
onclick: {
|
||||
enable: true,
|
||||
mode: "push",
|
||||
},
|
||||
resize: true,
|
||||
},
|
||||
modes: {
|
||||
grab: {
|
||||
distance: 312,
|
||||
line_linked: {
|
||||
opacity: 0.7,
|
||||
},
|
||||
},
|
||||
bubble: {
|
||||
distance: 400,
|
||||
size: 40,
|
||||
duration: 2,
|
||||
opacity: 8,
|
||||
speed: 3,
|
||||
},
|
||||
repulse: {
|
||||
distance: 200,
|
||||
duration: 0.4,
|
||||
},
|
||||
push: {
|
||||
particles_nb: 4,
|
||||
},
|
||||
remove: {
|
||||
particles_nb: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
retina_detect: true,
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div id="particles-js"></div>{" "}
|
||||
<div className="count-particles">
|
||||
<span className="js-count-particles">--</span> particles{" "}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ParticleBackground;
|
||||
143
src/app/components/Preferences/Preferences.tsx
Normal file
143
src/app/components/Preferences/Preferences.tsx
Normal file
@@ -0,0 +1,143 @@
|
||||
// File: src/components/PreferencesSelector.tsx
|
||||
"use client";
|
||||
|
||||
import { Button, Card, Checkbox, Flex, message, Space, Typography } from "antd";
|
||||
import { motion } from "framer-motion";
|
||||
import React, { useState } from "react";
|
||||
import styles from "./PreferencesSelector.module.css";
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
|
||||
type PreferenceOption = {
|
||||
id: string;
|
||||
label: string;
|
||||
description: string;
|
||||
};
|
||||
|
||||
const preferenceOptions: PreferenceOption[] = [
|
||||
{
|
||||
id: "branding",
|
||||
label: "Branding & Identity",
|
||||
description: "Visual identity, logo design, brand guidelines",
|
||||
},
|
||||
{
|
||||
id: "ecommerce",
|
||||
label: "E-commerce Solutions",
|
||||
description: "Online stores, payment gateways, inventory management",
|
||||
},
|
||||
{
|
||||
id: "seo",
|
||||
label: "SEO & Digital Marketing",
|
||||
description: "Search optimization, content strategy, analytics",
|
||||
},
|
||||
{
|
||||
id: "mobile",
|
||||
label: "Mobile Development",
|
||||
description: "iOS/Android apps, cross-platform solutions",
|
||||
},
|
||||
{
|
||||
id: "cloud",
|
||||
label: "Cloud Solutions",
|
||||
description: "Cloud infrastructure, migrations, DevOps",
|
||||
},
|
||||
{
|
||||
id: "ai",
|
||||
label: "AI & Machine Learning",
|
||||
description: "Data analytics, predictive models, automation",
|
||||
},
|
||||
];
|
||||
|
||||
interface PreferencesSelectorProps {
|
||||
onComplete: () => void;
|
||||
}
|
||||
|
||||
const PreferencesSelector: React.FC<PreferencesSelectorProps> = ({
|
||||
onComplete,
|
||||
}) => {
|
||||
const [selectedPreferences, setSelectedPreferences] = useState<string[]>([]);
|
||||
|
||||
const handleTogglePreference = (id: string) => {
|
||||
setSelectedPreferences((prev) =>
|
||||
prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id]
|
||||
);
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (selectedPreferences.length === 0) {
|
||||
message.warning("Please select at least one preference");
|
||||
return;
|
||||
}
|
||||
|
||||
// Store preferences in local storage
|
||||
localStorage.setItem(
|
||||
"userPreferences",
|
||||
JSON.stringify(selectedPreferences)
|
||||
);
|
||||
message.success("Preferences saved successfully!");
|
||||
onComplete();
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
className={styles.container}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
<Card className={styles.card}>
|
||||
<Title level={2}>Welcome to Tech Master</Title>
|
||||
<Text>
|
||||
Help us personalize your experience by selecting your interests:
|
||||
</Text>
|
||||
|
||||
<Space
|
||||
direction="vertical"
|
||||
size="large"
|
||||
className={styles.optionsContainer}
|
||||
>
|
||||
{preferenceOptions.map((option) => (
|
||||
<motion.div
|
||||
key={option.id}
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
<Card
|
||||
className={`${styles.optionCard} ${
|
||||
selectedPreferences.includes(option.id) ? styles.selected : ""
|
||||
}`}
|
||||
onClick={() => handleTogglePreference(option.id)}
|
||||
hoverable
|
||||
>
|
||||
<Flex align="center" gap="small">
|
||||
<Checkbox
|
||||
checked={selectedPreferences.includes(option.id)}
|
||||
onChange={() => handleTogglePreference(option.id)}
|
||||
/>
|
||||
<div>
|
||||
<Text strong>{option.label}</Text>
|
||||
<Text type="secondary" style={{ display: "block" }}>
|
||||
{option.description}
|
||||
</Text>
|
||||
</div>
|
||||
</Flex>
|
||||
</Card>
|
||||
</motion.div>
|
||||
))}
|
||||
</Space>
|
||||
|
||||
<Flex justify="center" className={styles.buttonContainer}>
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
onClick={handleSubmit}
|
||||
className={styles.continueButton}
|
||||
>
|
||||
Continue to Site
|
||||
</Button>
|
||||
</Flex>
|
||||
</Card>
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PreferencesSelector;
|
||||
@@ -0,0 +1,60 @@
|
||||
/* File: src/components/PreferencesSelector.module.css */
|
||||
|
||||
.container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: linear-gradient(135deg, #42475c 0%, #20222f 100%);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 90%;
|
||||
max-width: 600px;
|
||||
padding: 2rem;
|
||||
border-radius: 16px;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.optionsContainer {
|
||||
margin: 2rem 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.optionCard {
|
||||
transition: all 0.3s ease;
|
||||
border: 2px solid transparent;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.selected {
|
||||
border-color: #1890ff;
|
||||
background-color: rgba(24, 144, 255, 0.05);
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.continueButton {
|
||||
min-width: 200px;
|
||||
height: 48px;
|
||||
background: linear-gradient(90deg, #1890ff, #096dd9);
|
||||
border: none;
|
||||
border-radius: 24px;
|
||||
font-weight: 500;
|
||||
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.15);
|
||||
}
|
||||
|
||||
.continueButton:hover {
|
||||
background: linear-gradient(90deg, #40a9ff, #1890ff);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(24, 144, 255, 0.2);
|
||||
}
|
||||
265
src/app/components/ProjectsShowcase/ProjectsShowcase.tsx
Normal file
265
src/app/components/ProjectsShowcase/ProjectsShowcase.tsx
Normal file
@@ -0,0 +1,265 @@
|
||||
// File: src/components/home/ProjectsShowcase.tsx
|
||||
|
||||
import { EyeOutlined, LeftOutlined, RightOutlined } from "@ant-design/icons";
|
||||
import { Badge, Button, Card, Col, Row, Tag, Typography } from "antd";
|
||||
import { motion, useAnimation } from "framer-motion";
|
||||
import Image from "next/image";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import styles from "./ProjectsShowcaseSelector.module.css";
|
||||
|
||||
const { Title, Paragraph, Text } = Typography;
|
||||
|
||||
interface Project {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
imageUrl: string;
|
||||
category: string;
|
||||
technologies: string[];
|
||||
featured: boolean;
|
||||
}
|
||||
|
||||
// Sample project data
|
||||
const projectsData: Project[] = [
|
||||
{
|
||||
id: "p1",
|
||||
title: "FinTech Dashboard",
|
||||
description:
|
||||
"An AI-powered financial analytics platform with real-time data visualization and predictive insights.",
|
||||
imageUrl: "/api/placeholder/600/400",
|
||||
category: "Web Application",
|
||||
technologies: ["React", "Node.js", "TensorFlow", "AWS"],
|
||||
featured: true,
|
||||
},
|
||||
{
|
||||
id: "p2",
|
||||
title: "Healthcare Management System",
|
||||
description:
|
||||
"Comprehensive solution for managing patient records, appointments, and medical data with advanced security features.",
|
||||
imageUrl: "/api/placeholder/600/400",
|
||||
category: "Enterprise Software",
|
||||
technologies: ["Angular", ".NET Core", "SQL Server", "Azure"],
|
||||
featured: true,
|
||||
},
|
||||
{
|
||||
id: "p3",
|
||||
title: "E-commerce Marketplace",
|
||||
description:
|
||||
"Feature-rich online marketplace connecting vendors and customers with integrated payment processing and inventory management.",
|
||||
imageUrl: "/api/placeholder/600/400",
|
||||
category: "E-commerce",
|
||||
technologies: ["Next.js", "Stripe", "MongoDB", "GraphQL"],
|
||||
featured: true,
|
||||
},
|
||||
{
|
||||
id: "p4",
|
||||
title: "Smart City IoT Platform",
|
||||
description:
|
||||
"IoT ecosystem for urban monitoring and management, featuring real-time data collection and analytics.",
|
||||
imageUrl: "/api/placeholder/600/400",
|
||||
category: "IoT",
|
||||
technologies: ["Python", "MQTT", "Kubernetes", "TensorFlow"],
|
||||
featured: false,
|
||||
},
|
||||
{
|
||||
id: "p5",
|
||||
title: "Logistics Tracking System",
|
||||
description:
|
||||
"Real-time fleet management and package tracking solution with route optimization algorithms.",
|
||||
imageUrl: "/api/placeholder/600/400",
|
||||
category: "Mobile & Web",
|
||||
technologies: ["React Native", "Node.js", "PostgreSQL", "Google Maps API"],
|
||||
featured: false,
|
||||
},
|
||||
{
|
||||
id: "p6",
|
||||
title: "Virtual Learning Environment",
|
||||
description:
|
||||
"Interactive educational platform with personalized learning paths, video conferencing, and progress tracking.",
|
||||
imageUrl: "/api/placeholder/600/400",
|
||||
category: "Education",
|
||||
technologies: ["Vue.js", "Django", "WebRTC", "Docker"],
|
||||
featured: false,
|
||||
},
|
||||
];
|
||||
|
||||
const ProjectsShowcase: React.FC = () => {
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
const [visibleProjects, setVisibleProjects] = useState<Project[]>([]);
|
||||
const controls = useAnimation();
|
||||
|
||||
// Determine number of projects to show based on screen width
|
||||
const [projectsPerView, setProjectsPerView] = useState(3);
|
||||
|
||||
useEffect(() => {
|
||||
const handleResize = () => {
|
||||
if (window.innerWidth < 768) {
|
||||
setProjectsPerView(1);
|
||||
} else if (window.innerWidth < 992) {
|
||||
setProjectsPerView(2);
|
||||
} else {
|
||||
setProjectsPerView(3);
|
||||
}
|
||||
};
|
||||
|
||||
// Set initial state
|
||||
handleResize();
|
||||
|
||||
window.addEventListener("resize", handleResize);
|
||||
return () => window.removeEventListener("resize", handleResize);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// Update visible projects whenever currentIndex or projectsPerView changes
|
||||
setVisibleProjects(
|
||||
projectsData.slice(currentIndex, currentIndex + projectsPerView)
|
||||
);
|
||||
}, [currentIndex, projectsPerView]);
|
||||
|
||||
const handleNext = async () => {
|
||||
if (currentIndex + projectsPerView < projectsData.length) {
|
||||
await controls.start({
|
||||
x: "-100%",
|
||||
opacity: 0,
|
||||
transition: { duration: 0.3 },
|
||||
});
|
||||
setCurrentIndex((prev) => prev + 1);
|
||||
controls.start({
|
||||
x: 0,
|
||||
opacity: 1,
|
||||
transition: { duration: 0.3 },
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handlePrev = async () => {
|
||||
if (currentIndex > 0) {
|
||||
await controls.start({
|
||||
x: "100%",
|
||||
opacity: 0,
|
||||
transition: { duration: 0.3 },
|
||||
});
|
||||
setCurrentIndex((prev) => prev - 1);
|
||||
controls.start({
|
||||
x: 0,
|
||||
opacity: 1,
|
||||
transition: { duration: 0.3 },
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<section className={styles.projectsSection}>
|
||||
<div className={styles.container}>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
viewport={{ once: true }}
|
||||
className={styles.sectionHeader}
|
||||
>
|
||||
<Title level={2} className={styles.sectionTitle}>
|
||||
Our Work
|
||||
</Title>
|
||||
<Paragraph className={styles.sectionSubtitle}>
|
||||
Transforming ideas into powerful digital solutions
|
||||
</Paragraph>
|
||||
</motion.div>
|
||||
|
||||
<div className={styles.showcaseContainer}>
|
||||
<motion.div
|
||||
className={styles.projectsGrid}
|
||||
animate={controls}
|
||||
initial={{ opacity: 1, x: 0 }}
|
||||
>
|
||||
<Row gutter={[24, 24]}>
|
||||
{visibleProjects.map((project) => (
|
||||
<Col xs={24} md={24 / projectsPerView} key={project.id}>
|
||||
<motion.div
|
||||
whileHover={{ y: -10 }}
|
||||
transition={{ type: "spring", stiffness: 300 }}
|
||||
>
|
||||
<Card
|
||||
hoverable
|
||||
cover={
|
||||
<div className={styles.projectImageContainer}>
|
||||
<Image
|
||||
alt={project.title}
|
||||
src={project.imageUrl}
|
||||
className={styles.projectImage}
|
||||
width={400}
|
||||
height={400}
|
||||
/>
|
||||
<div className={styles.projectOverlay}>
|
||||
<Button
|
||||
type="primary"
|
||||
shape="circle"
|
||||
icon={<EyeOutlined />}
|
||||
className={styles.viewButton}
|
||||
/>
|
||||
</div>
|
||||
{project.featured && (
|
||||
<Badge.Ribbon
|
||||
text="Featured"
|
||||
className={styles.featuredBadge}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
className={styles.projectCard}
|
||||
>
|
||||
<div className={styles.categoryTag}>
|
||||
<Tag color="blue">{project.category}</Tag>
|
||||
</div>
|
||||
<Card.Meta
|
||||
title={project.title}
|
||||
description={project.description}
|
||||
/>
|
||||
<div className={styles.technologiesList}>
|
||||
{project.technologies.map((tech) => (
|
||||
<Tag key={tech} className={styles.techTag}>
|
||||
{tech}
|
||||
</Tag>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
</motion.div>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
</motion.div>
|
||||
|
||||
<div className={styles.navigationControls}>
|
||||
<Button
|
||||
shape="circle"
|
||||
icon={<LeftOutlined />}
|
||||
onClick={handlePrev}
|
||||
disabled={currentIndex === 0}
|
||||
className={styles.navButton}
|
||||
/>
|
||||
<Text className={styles.pageIndicator}>
|
||||
{currentIndex + 1}-
|
||||
{Math.min(currentIndex + projectsPerView, projectsData.length)} of{" "}
|
||||
{projectsData.length}
|
||||
</Text>
|
||||
<Button
|
||||
shape="circle"
|
||||
icon={<RightOutlined />}
|
||||
onClick={handleNext}
|
||||
disabled={currentIndex + projectsPerView >= projectsData.length}
|
||||
className={styles.navButton}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.viewAllContainer}>
|
||||
<Button type="primary" size="large" className={styles.viewAllButton}>
|
||||
View All Projects
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectsShowcase;
|
||||
@@ -0,0 +1,178 @@
|
||||
/* File: src/components/home/ProjectsShowcase.module.css */
|
||||
|
||||
.projectsSection {
|
||||
padding: 100px 0;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 16px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sectionHeader {
|
||||
text-align: center;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
font-size: 2.5rem !important;
|
||||
font-weight: 700 !important;
|
||||
margin-bottom: 16px !important;
|
||||
background: linear-gradient(90deg, #1890ff, #096dd9);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.sectionSubtitle {
|
||||
font-size: 1.1rem;
|
||||
color: #666;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.showcaseContainer {
|
||||
position: relative;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.projectsGrid {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.projectCard {
|
||||
height: 100%;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.projectImageContainer {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
height: 220px;
|
||||
}
|
||||
|
||||
.projectImage {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
|
||||
.projectCard:hover .projectImage {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.projectOverlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.projectCard:hover .projectOverlay {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.viewButton {
|
||||
background: #fff;
|
||||
color: #1890ff;
|
||||
border: none;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.viewButton:hover {
|
||||
background: #1890ff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.categoryTag {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.technologiesList {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.techTag {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.featuredBadge {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.navigationControls {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.navButton {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.pageIndicator {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.viewAllContainer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 48px;
|
||||
}
|
||||
|
||||
.viewAllButton {
|
||||
height: 48px;
|
||||
padding: 0 32px;
|
||||
border-radius: 24px;
|
||||
font-weight: 500;
|
||||
background: linear-gradient(90deg, #1890ff, #096dd9);
|
||||
border: none;
|
||||
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.15);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.viewAllButton:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(24, 144, 255, 0.2);
|
||||
background: linear-gradient(90deg, #40a9ff, #1890ff);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.projectsSection {
|
||||
padding: 60px 0;
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
font-size: 2rem !important;
|
||||
}
|
||||
|
||||
.projectImageContainer {
|
||||
height: 180px;
|
||||
}
|
||||
}
|
||||
185
src/app/components/Services/Services.tsx
Normal file
185
src/app/components/Services/Services.tsx
Normal file
@@ -0,0 +1,185 @@
|
||||
// File: src/components/home/ServicesSection.tsx
|
||||
"use client";
|
||||
|
||||
import {
|
||||
CloudOutlined,
|
||||
CodeOutlined,
|
||||
GlobalOutlined,
|
||||
LineChartOutlined,
|
||||
MobileOutlined,
|
||||
RobotOutlined,
|
||||
RocketOutlined,
|
||||
ShoppingOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { Button, Card, Col, Row, Typography } from 'antd';
|
||||
import { motion } from 'framer-motion';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import styles from './ServicesSelector.module.css';
|
||||
|
||||
const { Title, Paragraph } = Typography;
|
||||
|
||||
interface ServicesSectionProps {
|
||||
userPreferences: string[];
|
||||
}
|
||||
|
||||
interface Service {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
icon: React.ReactNode;
|
||||
preferenceMatches: string[];
|
||||
}
|
||||
|
||||
const allServices: Service[] = [
|
||||
{
|
||||
id: 'webdev',
|
||||
title: 'Web Development',
|
||||
description: 'Custom web applications with cutting-edge technologies and responsive design.',
|
||||
icon: <CodeOutlined className={styles.serviceIcon} />,
|
||||
preferenceMatches: ['ecommerce', 'cloud', 'seo']
|
||||
},
|
||||
{
|
||||
id: 'branding',
|
||||
title: 'Branding & Identity',
|
||||
description: 'Complete brand identity packages including logos, guidelines, and visual systems.',
|
||||
icon: <RocketOutlined className={styles.serviceIcon} />,
|
||||
preferenceMatches: ['branding', 'seo']
|
||||
},
|
||||
{
|
||||
id: 'ecom',
|
||||
title: 'E-commerce Solutions',
|
||||
description: 'Full-stack e-commerce platforms with secure payment integration and inventory management.',
|
||||
icon: <ShoppingOutlined className={styles.serviceIcon} />,
|
||||
preferenceMatches: ['ecommerce', 'branding']
|
||||
},
|
||||
{
|
||||
id: 'seo',
|
||||
title: 'SEO & Marketing',
|
||||
description: 'Data-driven digital marketing strategies to improve visibility and drive conversions.',
|
||||
icon: <LineChartOutlined className={styles.serviceIcon} />,
|
||||
preferenceMatches: ['seo', 'branding']
|
||||
},
|
||||
{
|
||||
id: 'mobile',
|
||||
title: 'Mobile Development',
|
||||
description: 'Native and cross-platform mobile applications for iOS and Android.',
|
||||
icon: <MobileOutlined className={styles.serviceIcon} />,
|
||||
preferenceMatches: ['mobile', 'ai']
|
||||
},
|
||||
{
|
||||
id: 'cloud',
|
||||
title: 'Cloud Solutions',
|
||||
description: 'Scalable cloud infrastructures, migrations, and DevOps automation.',
|
||||
icon: <CloudOutlined className={styles.serviceIcon} />,
|
||||
preferenceMatches: ['cloud', 'ai']
|
||||
},
|
||||
{
|
||||
id: 'ai',
|
||||
title: 'AI & Machine Learning',
|
||||
description: 'Custom AI solutions for automation, prediction, and data analysis.',
|
||||
icon: <RobotOutlined className={styles.serviceIcon} />,
|
||||
preferenceMatches: ['ai', 'cloud']
|
||||
},
|
||||
{
|
||||
id: 'global',
|
||||
title: 'Global IT Consulting',
|
||||
description: 'Strategic technology consulting to drive digital transformation and innovation.',
|
||||
icon: <GlobalOutlined className={styles.serviceIcon} />,
|
||||
preferenceMatches: ['cloud', 'branding', 'seo']
|
||||
},
|
||||
];
|
||||
|
||||
const ServicesSection: React.FC<ServicesSectionProps> = ({ userPreferences }) => {
|
||||
const [services, setServices] = useState<Service[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
// Sort services based on user preferences
|
||||
if (userPreferences.length > 0) {
|
||||
const sortedServices = [...allServices].sort((a, b) => {
|
||||
const aMatches = a.preferenceMatches.filter(pref => userPreferences.includes(pref)).length;
|
||||
const bMatches = b.preferenceMatches.filter(pref => userPreferences.includes(pref)).length;
|
||||
return bMatches - aMatches;
|
||||
});
|
||||
setServices(sortedServices);
|
||||
} else {
|
||||
// If no preferences, show all services in default order
|
||||
setServices(allServices);
|
||||
}
|
||||
}, [userPreferences]);
|
||||
|
||||
const containerVariants = {
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
staggerChildren: 0.1
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const itemVariants = {
|
||||
hidden: { y: 50, opacity: 0 },
|
||||
visible: {
|
||||
y: 0,
|
||||
opacity: 1,
|
||||
transition: { duration: 0.5 }
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<section className={styles.servicesSection}>
|
||||
<div className={styles.sectionBackground}>
|
||||
<div className={styles.glowOrb}></div>
|
||||
</div>
|
||||
<div className={styles.container}>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
viewport={{ once: true }}
|
||||
className={styles.sectionHeader}
|
||||
>
|
||||
<Title level={2} className={styles.sectionTitle}>Our Services</Title>
|
||||
<Paragraph className={styles.sectionSubtitle}>
|
||||
Innovative technology solutions customized for your business needs
|
||||
</Paragraph>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
variants={containerVariants}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={{ once: true }}
|
||||
>
|
||||
<Row gutter={[24, 24]}>
|
||||
{services.map((service) => (
|
||||
<Col xs={24} sm={12} lg={8} xl={6} key={service.id}>
|
||||
<motion.div variants={itemVariants}>
|
||||
<Card
|
||||
hoverable
|
||||
className={styles.serviceCard}
|
||||
cover={
|
||||
<div className={styles.serviceIconWrapper}>
|
||||
{service.icon}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Card.Meta
|
||||
title={service.title}
|
||||
description={service.description}
|
||||
/>
|
||||
<Button type="link" className={styles.learnMoreBtn}>
|
||||
Learn more
|
||||
</Button>
|
||||
</Card>
|
||||
</motion.div>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServicesSection;
|
||||
102
src/app/components/Services/ServicesSelector.module.css
Normal file
102
src/app/components/Services/ServicesSelector.module.css
Normal file
@@ -0,0 +1,102 @@
|
||||
/* File: src/components/home/ServicesSection.module.css */
|
||||
|
||||
.servicesSection {
|
||||
position: relative;
|
||||
padding: 100px 0;
|
||||
overflow: hidden;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 16px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.sectionBackground {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.glowOrb {
|
||||
position: absolute;
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(64, 169, 255, 0.2) 0%, rgba(24, 144, 255, 0.1) 50%, rgba(0, 0, 0, 0) 70%);
|
||||
top: -150px;
|
||||
right: -100px;
|
||||
filter: blur(50px);
|
||||
}
|
||||
|
||||
.sectionHeader {
|
||||
text-align: center;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
font-size: 2.5rem !important;
|
||||
font-weight: 700 !important;
|
||||
margin-bottom: 16px !important;
|
||||
background: linear-gradient(90deg, #1890ff, #096dd9);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.sectionSubtitle {
|
||||
font-size: 1.1rem;
|
||||
color: #666;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.serviceCard {
|
||||
height: 100%;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
border: none;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.serviceCard:hover {
|
||||
transform: translateY(-8px);
|
||||
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.serviceIconWrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 120px;
|
||||
background: linear-gradient(135deg, #f5f7fa 0%, #e4e7eb 100%);
|
||||
}
|
||||
|
||||
.serviceIcon {
|
||||
font-size: 3rem;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.learnMoreBtn {
|
||||
display: block;
|
||||
margin-top: 16px;
|
||||
padding: 0;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.servicesSection {
|
||||
padding: 60px 0;
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
font-size: 2rem !important;
|
||||
}
|
||||
}
|
||||
149
src/app/components/Testimonials/Testimonials.tsx
Normal file
149
src/app/components/Testimonials/Testimonials.tsx
Normal file
@@ -0,0 +1,149 @@
|
||||
// File: src/components/TestimonialsSection/TestimonialsSection.tsx
|
||||
"use client";
|
||||
|
||||
import { Avatar, Card, Carousel, Flex, Tag, Typography } from "antd";
|
||||
import { motion } from "framer-motion";
|
||||
import styles from "./TestimonialsSection.module.css";
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
|
||||
type Testimonial = {
|
||||
id: string;
|
||||
name: string;
|
||||
role: string;
|
||||
company: string;
|
||||
avatar: string;
|
||||
content: string;
|
||||
rating: number;
|
||||
project: string;
|
||||
technologies: string[];
|
||||
};
|
||||
|
||||
const testimonials: Testimonial[] = [
|
||||
{
|
||||
id: "1",
|
||||
name: "Ahmed Al-Maktoum",
|
||||
role: "CTO",
|
||||
company: "Dubai Tech Innovations",
|
||||
avatar: "https://randomuser.me/api/portraits/men/32.jpg",
|
||||
content:
|
||||
"Tech Master transformed our e-commerce platform with their cutting-edge solutions. The team's expertise in AI integration helped us increase conversions by 40%.",
|
||||
rating: 5,
|
||||
project: "E-commerce AI Optimization",
|
||||
technologies: ["AI", "React", "Node.js"],
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "Sarah Johnson",
|
||||
role: "Digital Director",
|
||||
company: "Stellar Communications",
|
||||
avatar: "https://randomuser.me/api/portraits/women/44.jpg",
|
||||
content:
|
||||
"Their cloud migration strategy saved us thousands in operational costs. The most reliable IT partner we've worked with in the region.",
|
||||
rating: 5,
|
||||
project: "Cloud Infrastructure Migration",
|
||||
technologies: ["AWS", "Terraform", "Kubernetes"],
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
name: "Raj Patel",
|
||||
role: "Founder",
|
||||
company: "Neuralink Dubai",
|
||||
avatar: "https://randomuser.me/api/portraits/men/67.jpg",
|
||||
content:
|
||||
"The blockchain solution they developed for our supply chain brought unprecedented transparency to our operations. Exceptional work!",
|
||||
rating: 4,
|
||||
project: "Blockchain Supply Chain",
|
||||
technologies: ["Ethereum", "Solidity", "IPFS"],
|
||||
},
|
||||
];
|
||||
|
||||
const TestimonialsSection = () => {
|
||||
const renderStars = (rating: number) => {
|
||||
return (
|
||||
<Flex gap="small" style={{ marginTop: 8 }}>
|
||||
{[...Array(5)].map((_, i) => (
|
||||
<span
|
||||
key={i}
|
||||
className={i < rating ? styles.filledStar : styles.emptyStar}
|
||||
>
|
||||
★
|
||||
</span>
|
||||
))}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.testimonialsSection}>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.sectionHeader}>
|
||||
<Title level={2} className={styles.sectionTitle}>
|
||||
Client Testimonials
|
||||
</Title>
|
||||
<Text className={styles.sectionSubtitle}>
|
||||
Hear what industry leaders say about our transformative solutions
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<div className={styles.showcaseContainer}>
|
||||
<Carousel
|
||||
autoplay
|
||||
dots={{ className: styles.carouselDots }}
|
||||
className={styles.testimonialsCarousel}
|
||||
>
|
||||
{testimonials.map((testimonial) => (
|
||||
<motion.div
|
||||
key={testimonial.id}
|
||||
className={styles.testimonialItem}
|
||||
whileHover={{ y: -5 }}
|
||||
>
|
||||
<Card className={styles.testimonialCard}>
|
||||
<Flex vertical gap={24}>
|
||||
<Flex align="center" gap={16}>
|
||||
<Avatar
|
||||
src={testimonial.avatar}
|
||||
size={64}
|
||||
className={styles.avatar}
|
||||
/>
|
||||
<Flex vertical>
|
||||
<Text strong className={styles.clientName}>
|
||||
{testimonial.name}
|
||||
</Text>
|
||||
<Text type="secondary" className={styles.clientTitle}>
|
||||
{testimonial.role}, {testimonial.company}
|
||||
</Text>
|
||||
{renderStars(testimonial.rating)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<Text className={styles.testimonialContent}>
|
||||
{testimonial.content}
|
||||
</Text>
|
||||
|
||||
<div className={styles.projectInfo}>
|
||||
<Text strong className={styles.projectLabel}>
|
||||
Project:
|
||||
</Text>
|
||||
<Text>{testimonial.project}</Text>
|
||||
</div>
|
||||
|
||||
<div className={styles.technologiesList}>
|
||||
{testimonial.technologies.map((tech) => (
|
||||
<Tag key={tech} className={styles.techTag}>
|
||||
{tech}
|
||||
</Tag>
|
||||
))}
|
||||
</div>
|
||||
</Flex>
|
||||
</Card>
|
||||
</motion.div>
|
||||
))}
|
||||
</Carousel>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TestimonialsSection;
|
||||
164
src/app/components/Testimonials/TestimonialsSection.module.css
Normal file
164
src/app/components/Testimonials/TestimonialsSection.module.css
Normal file
@@ -0,0 +1,164 @@
|
||||
/* File: src/components/TestimonialsSection/TestimonialsSection.module.css */
|
||||
.testimonialsSection {
|
||||
padding: 100px 0;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 16px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sectionHeader {
|
||||
text-align: center;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
font-size: 2.5rem !important;
|
||||
font-weight: 700 !important;
|
||||
margin-bottom: 16px !important;
|
||||
background: linear-gradient(90deg, #1890ff, #096dd9);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.sectionSubtitle {
|
||||
font-size: 1.1rem;
|
||||
color: #666;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.showcaseContainer {
|
||||
position: relative;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.testimonialsCarousel {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.testimonialItem {
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.testimonialCard {
|
||||
height: 100%;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||
border: none;
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.clientName {
|
||||
font-size: 1.2rem;
|
||||
color: #333;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.clientTitle {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.testimonialContent {
|
||||
font-size: 1rem;
|
||||
color: #555;
|
||||
line-height: 1.6;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.projectInfo {
|
||||
margin-top: 16px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.projectLabel {
|
||||
background: var(--primary);
|
||||
-webkit-background-clip: text; /* For Safari */
|
||||
background-clip: text;
|
||||
color: transparent !important; /* Hide original text color */
|
||||
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.technologiesList {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.techTag {
|
||||
margin: 0;
|
||||
background: #f5f5f5;
|
||||
border-color: #d9d9d9;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.filledStar {
|
||||
color: #faad14;
|
||||
}
|
||||
|
||||
.emptyStar {
|
||||
color: #d9d9d9;
|
||||
}
|
||||
|
||||
.carouselDots li button {
|
||||
background: #d9d9d9 !important;
|
||||
width: 10px !important;
|
||||
height: 10px !important;
|
||||
border-radius: 50% !important;
|
||||
}
|
||||
|
||||
.carouselDots li.slick-active button {
|
||||
background: #1890ff !important;
|
||||
}
|
||||
|
||||
.viewAllContainer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 48px;
|
||||
}
|
||||
|
||||
.viewAllButton {
|
||||
height: 48px;
|
||||
padding: 0 32px;
|
||||
border-radius: 24px;
|
||||
font-weight: 500;
|
||||
background: linear-gradient(90deg, #1890ff, #096dd9);
|
||||
color: white;
|
||||
border: none;
|
||||
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.15);
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.viewAllButton:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(24, 144, 255, 0.2);
|
||||
background: linear-gradient(90deg, #40a9ff, #1890ff);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.testimonialsSection {
|
||||
padding: 60px 0;
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
font-size: 2rem !important;
|
||||
}
|
||||
|
||||
.testimonialCard {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
BIN
src/app/favicon.ico
Normal file
BIN
src/app/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
86
src/app/globals.css
Normal file
86
src/app/globals.css
Normal file
@@ -0,0 +1,86 @@
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #171717;
|
||||
--primary: linear-gradient(135deg, #6e48aa 0%, #9d50bb 100%);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: #0a0a0a;
|
||||
--foreground: #ededed;
|
||||
}
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
max-width: 100vw;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
color: var(--foreground);
|
||||
background: var(--background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
color-scheme: dark;
|
||||
}
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: block;
|
||||
vertical-align: bottom;
|
||||
} /* ---- particles.js container ---- */
|
||||
#particles-js {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: linear-gradient(135deg, #6e48aa 0%, #9d50bb 100%);
|
||||
}
|
||||
|
||||
.count-particles {
|
||||
background: #000022;
|
||||
position: absolute;
|
||||
top: 48px;
|
||||
left: 0;
|
||||
width: 80px;
|
||||
color: #13e8e9;
|
||||
font-size: 0.8em;
|
||||
text-align: left;
|
||||
text-indent: 4px;
|
||||
line-height: 14px;
|
||||
padding-bottom: 2px;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
.js-count-particles {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
#stats,
|
||||
.count-particles {
|
||||
-webkit-user-select: none;
|
||||
margin-top: 5px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
#stats {
|
||||
border-radius: 3px 3px 0 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.count-particles {
|
||||
border-radius: 0 0 3px 3px;
|
||||
}
|
||||
49
src/app/layout.tsx
Normal file
49
src/app/layout.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
// src/app/layout.tsx
|
||||
import { ConfigProvider } from "antd";
|
||||
import type { Metadata } from "next";
|
||||
import { Inter } from "next/font/google";
|
||||
import Header from "./components/Header/Header";
|
||||
import "./globals.css";
|
||||
import { themeConfig } from "./theme/themeConfig";
|
||||
|
||||
// Modern font (Inter + Orbitron backup)
|
||||
const inter = Inter({ subsets: ["latin"] });
|
||||
const orbitron = {
|
||||
className: "font-orbitron",
|
||||
style:
|
||||
"@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap');",
|
||||
};
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Tech Master | Dubai To Stars",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
{/* ThreeJS CDN */}
|
||||
<script
|
||||
src="http://cdn.jsdelivr.net/particles.js/2.0.0/particles.min.js"
|
||||
async
|
||||
></script>
|
||||
<script
|
||||
src="http://threejs.org/examples/js/libs/stats.min.js"
|
||||
async
|
||||
></script>
|
||||
{/* Orbitron Font */}
|
||||
<style>{orbitron.style}</style>
|
||||
</head>
|
||||
<body
|
||||
className={`${inter.className} bg-gradient-to-br from-[#0F0525] to-[#2A0B45]`}
|
||||
>
|
||||
<Header />
|
||||
<ConfigProvider theme={themeConfig}>{children}</ConfigProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
42
src/app/page.module.css
Normal file
42
src/app/page.module.css
Normal file
@@ -0,0 +1,42 @@
|
||||
/* File: src/styles/Home.module.css */
|
||||
|
||||
.main {
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.loaderContainer {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: linear-gradient(135deg, #42475C 0%, #20222F 100%);
|
||||
}
|
||||
|
||||
.loaderText {
|
||||
margin-top: 20px;
|
||||
color: white;
|
||||
opacity: 0.8;
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% { opacity: 0.6; }
|
||||
50% { opacity: 1; }
|
||||
100% { opacity: 0.6; }
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 80px 16px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.section {
|
||||
padding: 60px 16px;
|
||||
}
|
||||
}
|
||||
72
src/app/page.tsx
Normal file
72
src/app/page.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
// File: src/pages/index.tsx
|
||||
"use client";
|
||||
|
||||
import { Spin, Typography } from "antd";
|
||||
import { useEffect, useState } from "react";
|
||||
import ContactSection from "./components/Contact/Contact";
|
||||
import HeroSection from "./components/Hero/HeroSection";
|
||||
import PreferencesSelector from "./components/Preferences/Preferences";
|
||||
import ProjectsShowcase from "./components/ProjectsShowcase/ProjectsShowcase";
|
||||
import ServicesSection from "./components/Services/Services";
|
||||
import TestimonialsSection from "./components/Testimonials/Testimonials";
|
||||
import styles from "./page.module.css";
|
||||
|
||||
const { Title } = Typography;
|
||||
|
||||
export default function Home() {
|
||||
const [showPreferences, setShowPreferences] = useState(true);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [userPreferences, setUserPreferences] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
// Check if preferences already exist in localStorage
|
||||
const storedPreferences = localStorage.getItem("userPreferences");
|
||||
|
||||
if (storedPreferences) {
|
||||
setUserPreferences(JSON.parse(storedPreferences));
|
||||
setShowPreferences(false);
|
||||
}
|
||||
|
||||
// Simulate loading of resources
|
||||
const timer = setTimeout(() => {
|
||||
setLoading(false);
|
||||
}, 1500);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
const handlePreferencesComplete = () => {
|
||||
const storedPreferences = localStorage.getItem("userPreferences");
|
||||
if (storedPreferences) {
|
||||
setUserPreferences(JSON.parse(storedPreferences));
|
||||
}
|
||||
setShowPreferences(false);
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className={styles.loaderContainer}>
|
||||
<Spin size="large" />
|
||||
<Title level={4} className={styles.loaderText}>
|
||||
Preparing Tech Master Experience...
|
||||
</Title>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{showPreferences && (
|
||||
<PreferencesSelector onComplete={handlePreferencesComplete} />
|
||||
)}
|
||||
|
||||
<main className={styles.main}>
|
||||
<HeroSection />
|
||||
<ServicesSection userPreferences={userPreferences} />
|
||||
<ProjectsShowcase />
|
||||
<TestimonialsSection />
|
||||
<ContactSection />
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
45
src/app/theme/themeConfig.ts
Normal file
45
src/app/theme/themeConfig.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
// src/app/theme/themeConfig.ts
|
||||
import type { ThemeConfig } from "antd";
|
||||
|
||||
// Cosmic Gradient Palette (Bright/Futuristic)
|
||||
export const gradientColors = {
|
||||
primary: "linear-gradient(135deg, #6e48aa 0%, #9d50bb 100%)",
|
||||
secondary: "linear-gradient(135deg, #00C1D4 0%, #FF5F6D 100%)",
|
||||
darkSpace: "linear-gradient(to right, #0F0525, #2A0B45)",
|
||||
};
|
||||
|
||||
// AntD Theme Configuration
|
||||
export const themeConfig: ThemeConfig = {
|
||||
token: {
|
||||
colorPrimary: "#6e48aa", // Cosmic purple
|
||||
colorLink: "#9d50bb", // Nebula pink
|
||||
fontFamily: "Inter, Orbitron, sans-serif",
|
||||
borderRadius: 8,
|
||||
// Futuristic button styles
|
||||
controlHeight: 40,
|
||||
},
|
||||
components: {
|
||||
Button: {
|
||||
colorPrimary: gradientColors.primary,
|
||||
colorPrimaryHover: "linear-gradient(135deg, #9d50bb 0%, #FF5F6D 100%)",
|
||||
colorPrimaryActive: "#00C1D4",
|
||||
lineWidth: 0,
|
||||
},
|
||||
Card: {
|
||||
colorPrimary: gradientColors.primary,
|
||||
boxShadow: "0 8px 32px rgba(110, 72, 170, 0.3)",
|
||||
borderRadiusLG: 12,
|
||||
},
|
||||
Typography: {
|
||||
colorPrimary: gradientColors.primary,
|
||||
colorTextHeading: gradientColors.primary,
|
||||
colorLink: gradientColors.primary, // Nebula pink
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// CSS-in-JS Utilities (For global use)
|
||||
export const futuristicStyles = {
|
||||
textGradient: `background: ${gradientColors.secondary}; -webkit-background-clip: text; -webkit-text-fill-color: transparent;`,
|
||||
glassEffect: `background: rgba(255, 255, 255, 0.05); backdrop-filter: blur(12px); border: 1px solid rgba(255, 255, 255, 0.1);`,
|
||||
};
|
||||
Reference in New Issue
Block a user