Initial commit 🌟

This commit is contained in:
Mohammed Al-yaseen
2025-04-06 20:03:35 +03:00
commit fbd966a3fd
34 changed files with 5884 additions and 0 deletions

View 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;

View 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;
}
}

View 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;
}
}

View 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;

View 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;
}
}

View 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;

View 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;

View 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;

View File

@@ -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);
}

View 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;

View File

@@ -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;
}
}

View 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;

View 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;
}
}

View 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;

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

86
src/app/globals.css Normal file
View 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
View 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
View 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
View 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>
</>
);
}

View 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);`,
};