enhance ssr, add routes and enhance the header styles
This commit is contained in:
32
src/app/about/layout.tsx
Normal file
32
src/app/about/layout.tsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "About Us | Tech Master - Award-Winning IT Solutions Dubai",
|
||||||
|
description: "Learn about Tech Master, an award-winning Dubai-based technology agency specializing in digital transformation, web development, and innovative IT solutions since 2020.",
|
||||||
|
keywords: [
|
||||||
|
"about Tech Master",
|
||||||
|
"Dubai IT company",
|
||||||
|
"award-winning tech agency",
|
||||||
|
"digital transformation company",
|
||||||
|
"web development company Dubai",
|
||||||
|
"IT solutions provider",
|
||||||
|
"tech company Dubai",
|
||||||
|
"software development company"
|
||||||
|
],
|
||||||
|
openGraph: {
|
||||||
|
title: "About Us | Tech Master - Award-Winning IT Solutions Dubai",
|
||||||
|
description: "Learn about Tech Master, an award-winning Dubai-based technology agency specializing in digital transformation and innovative IT solutions.",
|
||||||
|
url: "https://tech-masters.guru/about",
|
||||||
|
},
|
||||||
|
alternates: {
|
||||||
|
canonical: "/about",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function AboutLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
253
src/app/about/page.tsx
Normal file
253
src/app/about/page.tsx
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import {
|
||||||
|
CheckCircleOutlined,
|
||||||
|
GlobalOutlined,
|
||||||
|
RocketOutlined,
|
||||||
|
StarOutlined,
|
||||||
|
TeamOutlined,
|
||||||
|
TrophyOutlined
|
||||||
|
} from "@ant-design/icons";
|
||||||
|
import { Avatar, Card, Col, Row, Typography } from "antd";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
|
||||||
|
const { Title, Paragraph } = Typography;
|
||||||
|
|
||||||
|
export default function AboutPage() {
|
||||||
|
const stats = [
|
||||||
|
{ icon: <TrophyOutlined />, number: "50+", label: "Projects Completed" },
|
||||||
|
{ icon: <GlobalOutlined />, number: "25+", label: "Happy Clients" },
|
||||||
|
{ icon: <TeamOutlined />, number: "15+", label: "Expert Developers" },
|
||||||
|
{ icon: <RocketOutlined />, number: "3+", label: "Years Experience" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const values = [
|
||||||
|
{
|
||||||
|
title: "Innovation First",
|
||||||
|
description: "We stay ahead of technology trends to deliver cutting-edge solutions that give our clients a competitive advantage.",
|
||||||
|
icon: <RocketOutlined />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Quality Excellence",
|
||||||
|
description: "Every project is crafted with attention to detail, ensuring the highest standards of quality and performance.",
|
||||||
|
icon: <StarOutlined />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Client Success",
|
||||||
|
description: "Your success is our success. We work closely with clients to understand their needs and deliver solutions that exceed expectations.",
|
||||||
|
icon: <CheckCircleOutlined />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Transparency",
|
||||||
|
description: "We believe in open communication and transparent processes, keeping you informed at every step of your project.",
|
||||||
|
icon: <GlobalOutlined />
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="pt-20">
|
||||||
|
{/* Hero Section */}
|
||||||
|
<section className="py-20 bg-gradient-to-br from-[#0F0525] to-[#2A0B45] text-white">
|
||||||
|
<div className="max-w-6xl mx-auto px-4">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.8 }}
|
||||||
|
className="text-center"
|
||||||
|
>
|
||||||
|
<Title level={1} className="text-5xl font-bold mb-6 text-white">
|
||||||
|
About Tech Master
|
||||||
|
</Title>
|
||||||
|
<Paragraph className="text-xl text-gray-300 max-w-3xl mx-auto">
|
||||||
|
From Dubai to the stars, we're an award-winning technology agency
|
||||||
|
dedicated to transforming businesses through innovative digital solutions.
|
||||||
|
</Paragraph>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Stats Section */}
|
||||||
|
<section className="py-16 bg-white">
|
||||||
|
<div className="max-w-6xl mx-auto px-4">
|
||||||
|
<Row gutter={[32, 32]} justify="center">
|
||||||
|
{stats.map((stat, index) => (
|
||||||
|
<Col xs={24} sm={12} md={6} key={index}>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6, delay: index * 0.1 }}
|
||||||
|
className="text-center"
|
||||||
|
>
|
||||||
|
<div className="text-4xl text-[#6e48aa] mb-2">
|
||||||
|
{stat.icon}
|
||||||
|
</div>
|
||||||
|
<div className="text-3xl font-bold text-gray-800 mb-1">
|
||||||
|
{stat.number}
|
||||||
|
</div>
|
||||||
|
<div className="text-gray-600">{stat.label}</div>
|
||||||
|
</motion.div>
|
||||||
|
</Col>
|
||||||
|
))}
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Story Section */}
|
||||||
|
<section className="py-16 bg-gray-50">
|
||||||
|
<div className="max-w-6xl mx-auto px-4">
|
||||||
|
<Row gutter={[48, 48]} align="middle">
|
||||||
|
<Col xs={24} lg={12}>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: -30 }}
|
||||||
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{ duration: 0.8 }}
|
||||||
|
>
|
||||||
|
<Title level={2} className="text-4xl font-bold mb-6">
|
||||||
|
Our Story
|
||||||
|
</Title>
|
||||||
|
<Paragraph className="text-lg text-gray-700 mb-6">
|
||||||
|
Founded in 2020, Tech Master emerged from a vision to bridge the gap
|
||||||
|
between traditional business practices and cutting-edge technology.
|
||||||
|
Based in Dubai, we've grown from a small startup to an award-winning
|
||||||
|
technology agency serving clients across the UAE and beyond.
|
||||||
|
</Paragraph>
|
||||||
|
<Paragraph className="text-lg text-gray-700">
|
||||||
|
Our journey has been marked by continuous innovation, unwavering
|
||||||
|
commitment to quality, and a deep understanding of our clients' needs.
|
||||||
|
We believe that technology should be an enabler, not a barrier,
|
||||||
|
and we work tirelessly to make digital transformation accessible
|
||||||
|
to businesses of all sizes.
|
||||||
|
</Paragraph>
|
||||||
|
</motion.div>
|
||||||
|
</Col>
|
||||||
|
<Col xs={24} lg={12}>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: 30 }}
|
||||||
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{ duration: 0.8 }}
|
||||||
|
className="text-center"
|
||||||
|
>
|
||||||
|
<div className="w-64 h-64 mx-auto bg-gradient-to-br from-[#6e48aa] to-[#9d50bb] rounded-full flex items-center justify-center">
|
||||||
|
<GlobalOutlined className="text-6xl text-white" />
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Values Section */}
|
||||||
|
<section className="py-16 bg-white">
|
||||||
|
<div className="max-w-6xl mx-auto px-4">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.8 }}
|
||||||
|
className="text-center mb-12"
|
||||||
|
>
|
||||||
|
<Title level={2} className="text-4xl font-bold mb-4">
|
||||||
|
Our Values
|
||||||
|
</Title>
|
||||||
|
<Paragraph className="text-lg text-gray-600 max-w-2xl mx-auto">
|
||||||
|
These core values guide everything we do and shape the way we
|
||||||
|
approach every project and client relationship.
|
||||||
|
</Paragraph>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<Row gutter={[32, 32]}>
|
||||||
|
{values.map((value, index) => (
|
||||||
|
<Col xs={24} sm={12} lg={6} key={index}>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6, delay: index * 0.1 }}
|
||||||
|
>
|
||||||
|
<Card className="h-full text-center hover:shadow-lg transition-shadow">
|
||||||
|
<div className="text-4xl text-[#6e48aa] mb-4">
|
||||||
|
{value.icon}
|
||||||
|
</div>
|
||||||
|
<Title level={4} className="mb-3">
|
||||||
|
{value.title}
|
||||||
|
</Title>
|
||||||
|
<Paragraph className="text-gray-600">
|
||||||
|
{value.description}
|
||||||
|
</Paragraph>
|
||||||
|
</Card>
|
||||||
|
</motion.div>
|
||||||
|
</Col>
|
||||||
|
))}
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Team Section */}
|
||||||
|
<section className="py-16 bg-gray-50">
|
||||||
|
<div className="max-w-6xl mx-auto px-4">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.8 }}
|
||||||
|
className="text-center mb-12"
|
||||||
|
>
|
||||||
|
<Title level={2} className="text-4xl font-bold mb-4">
|
||||||
|
Our Team
|
||||||
|
</Title>
|
||||||
|
<Paragraph className="text-lg text-gray-600 max-w-2xl mx-auto">
|
||||||
|
Meet the passionate professionals behind Tech Master's success.
|
||||||
|
Our diverse team brings together expertise from various domains
|
||||||
|
to deliver exceptional results.
|
||||||
|
</Paragraph>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<Row gutter={[32, 32]} justify="center">
|
||||||
|
<Col xs={24} sm={12} md={8}>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6 }}
|
||||||
|
className="text-center"
|
||||||
|
>
|
||||||
|
<Avatar size={120} src="https://randomuser.me/api/portraits/men/32.jpg" className="mb-4" />
|
||||||
|
<Title level={4} className="mb-2">Ahmed Hassan</Title>
|
||||||
|
<Paragraph className="text-gray-600 mb-2">CEO & Founder</Paragraph>
|
||||||
|
<Paragraph className="text-sm text-gray-500">
|
||||||
|
Visionary leader with 10+ years in digital transformation
|
||||||
|
</Paragraph>
|
||||||
|
</motion.div>
|
||||||
|
</Col>
|
||||||
|
<Col xs={24} sm={12} md={8}>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6, delay: 0.1 }}
|
||||||
|
className="text-center"
|
||||||
|
>
|
||||||
|
<Avatar size={120} src="https://randomuser.me/api/portraits/women/44.jpg" className="mb-4" />
|
||||||
|
<Title level={4} className="mb-2">Sarah Johnson</Title>
|
||||||
|
<Paragraph className="text-gray-600 mb-2">CTO</Paragraph>
|
||||||
|
<Paragraph className="text-sm text-gray-500">
|
||||||
|
Technical expert specializing in AI and cloud solutions
|
||||||
|
</Paragraph>
|
||||||
|
</motion.div>
|
||||||
|
</Col>
|
||||||
|
<Col xs={24} sm={12} md={8}>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6, delay: 0.2 }}
|
||||||
|
className="text-center"
|
||||||
|
>
|
||||||
|
<Avatar size={120} src="https://randomuser.me/api/portraits/men/67.jpg" className="mb-4" />
|
||||||
|
<Title level={4} className="mb-2">Raj Patel</Title>
|
||||||
|
<Paragraph className="text-gray-600 mb-2">Lead Developer</Paragraph>
|
||||||
|
<Paragraph className="text-sm text-gray-500">
|
||||||
|
Full-stack developer with expertise in modern frameworks
|
||||||
|
</Paragraph>
|
||||||
|
</motion.div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,30 +1,10 @@
|
|||||||
// File: src/components/home/ProjectsShowcase.tsx
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CloseOutlined,
|
Typography
|
||||||
EyeOutlined,
|
|
||||||
GithubOutlined,
|
|
||||||
LeftOutlined,
|
|
||||||
LinkOutlined,
|
|
||||||
RightOutlined,
|
|
||||||
} from "@ant-design/icons";
|
|
||||||
import {
|
|
||||||
Badge,
|
|
||||||
Button,
|
|
||||||
Card,
|
|
||||||
Carousel,
|
|
||||||
Col,
|
|
||||||
Modal,
|
|
||||||
Row,
|
|
||||||
Tag,
|
|
||||||
Typography,
|
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import { AnimatePresence, motion, useAnimation } from "framer-motion";
|
import ProjectsShowcaseClient from "./ProjectsShowcaseClient";
|
||||||
import Image from "next/image";
|
|
||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import styles from "./ProjectsShowcaseSelector.module.css";
|
import styles from "./ProjectsShowcaseSelector.module.css";
|
||||||
|
|
||||||
const { Title, Paragraph, Text } = Typography;
|
const { Title, Paragraph } = Typography;
|
||||||
|
|
||||||
interface Project {
|
interface Project {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -273,331 +253,20 @@ const projectsData: Project[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const ProjectsShowcase: React.FC = () => {
|
const ProjectsShowcase: React.FC = () => {
|
||||||
const [currentIndex, setCurrentIndex] = useState(0);
|
|
||||||
const [visibleProjects, setVisibleProjects] = useState<Project[]>([]);
|
|
||||||
const [selectedProject, setSelectedProject] = useState<Project | null>(null);
|
|
||||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
|
||||||
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 },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleProjectClick = (project: Project) => {
|
|
||||||
setSelectedProject(project);
|
|
||||||
setIsModalVisible(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleModalClose = () => {
|
|
||||||
setIsModalVisible(false);
|
|
||||||
setTimeout(() => {
|
|
||||||
setSelectedProject(null);
|
|
||||||
}, 300);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={styles.projectsSection}>
|
<section className={styles.projectsSection}>
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<motion.div
|
<div className={styles.sectionHeader}>
|
||||||
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}>
|
<Title level={2} className={styles.sectionTitle}>
|
||||||
Our Work
|
Our Work
|
||||||
</Title>
|
</Title>
|
||||||
<Paragraph className={styles.sectionSubtitle}>
|
<Paragraph className={styles.sectionSubtitle}>
|
||||||
Transforming ideas into powerful digital solutions
|
Transforming ideas into powerful digital solutions
|
||||||
</Paragraph>
|
</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
|
|
||||||
onClick={() => handleProjectClick(project)}
|
|
||||||
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>
|
||||||
|
|
||||||
<div className={styles.viewAllContainer}>
|
<ProjectsShowcaseClient projects={projectsData} />
|
||||||
<Button type="primary" size="large" className={styles.viewAllButton}>
|
|
||||||
View All Projects
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Project Details Modal */}
|
|
||||||
<AnimatePresence>
|
|
||||||
{isModalVisible && selectedProject && (
|
|
||||||
<Modal
|
|
||||||
open={isModalVisible}
|
|
||||||
onCancel={handleModalClose}
|
|
||||||
footer={null}
|
|
||||||
width={1000}
|
|
||||||
className={styles.projectModal}
|
|
||||||
closeIcon={<CloseOutlined className={styles.closeIcon} />}
|
|
||||||
>
|
|
||||||
<motion.div
|
|
||||||
initial={{ opacity: 0, scale: 0.8 }}
|
|
||||||
animate={{ opacity: 1, scale: 1 }}
|
|
||||||
exit={{ opacity: 0, scale: 0.8 }}
|
|
||||||
transition={{ duration: 0.3 }}
|
|
||||||
className={styles.modalContent}
|
|
||||||
>
|
|
||||||
<div className={styles.modalHeader}>
|
|
||||||
<div className={styles.modalTitleSection}>
|
|
||||||
<Title level={2} className={styles.modalTitle}>
|
|
||||||
{selectedProject.title}
|
|
||||||
</Title>
|
|
||||||
<Tag color="blue" className={styles.modalCategory}>
|
|
||||||
{selectedProject.category}
|
|
||||||
</Tag>
|
|
||||||
</div>
|
|
||||||
<div className={styles.modalActions}>
|
|
||||||
{selectedProject.liveUrl && (
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
icon={<LinkOutlined />}
|
|
||||||
href={selectedProject.liveUrl}
|
|
||||||
target="_blank"
|
|
||||||
className={styles.actionButton}
|
|
||||||
>
|
|
||||||
Live Demo
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{selectedProject.githubUrl && (
|
|
||||||
<Button
|
|
||||||
icon={<GithubOutlined />}
|
|
||||||
href={selectedProject.githubUrl}
|
|
||||||
target="_blank"
|
|
||||||
className={styles.actionButton}
|
|
||||||
>
|
|
||||||
View Code
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.modalBody}>
|
|
||||||
<div className={styles.projectImages}>
|
|
||||||
<Carousel
|
|
||||||
autoplay
|
|
||||||
dots={{ className: styles.carouselDots }}
|
|
||||||
className={styles.imageCarousel}
|
|
||||||
>
|
|
||||||
{selectedProject.images.map((image, index) => (
|
|
||||||
<div key={index} className={styles.carouselItem}>
|
|
||||||
<Image
|
|
||||||
src={image}
|
|
||||||
alt={`${selectedProject.title} - Image ${index + 1}`}
|
|
||||||
width={800}
|
|
||||||
height={500}
|
|
||||||
className={styles.modalImage}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</Carousel>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.projectDetails}>
|
|
||||||
<div className={styles.detailSection}>
|
|
||||||
<Title level={4} className={styles.sectionTitle}>
|
|
||||||
Project Overview
|
|
||||||
</Title>
|
|
||||||
<Paragraph className={styles.projectDescription}>
|
|
||||||
{selectedProject.detailedDescription}
|
|
||||||
</Paragraph>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.detailGrid}>
|
|
||||||
<div className={styles.detailSection}>
|
|
||||||
<Title level={4} className={styles.sectionTitle}>
|
|
||||||
Key Features
|
|
||||||
</Title>
|
|
||||||
<ul className={styles.featuresList}>
|
|
||||||
{selectedProject.features.map((feature, index) => (
|
|
||||||
<motion.li
|
|
||||||
key={index}
|
|
||||||
initial={{ opacity: 0, x: -20 }}
|
|
||||||
animate={{ opacity: 1, x: 0 }}
|
|
||||||
transition={{ delay: index * 0.1 }}
|
|
||||||
className={styles.featureItem}
|
|
||||||
>
|
|
||||||
{feature}
|
|
||||||
</motion.li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.detailSection}>
|
|
||||||
<Title level={4} className={styles.sectionTitle}>
|
|
||||||
Project Details
|
|
||||||
</Title>
|
|
||||||
<div className={styles.projectInfo}>
|
|
||||||
<div className={styles.infoItem}>
|
|
||||||
<Text strong>Duration:</Text>
|
|
||||||
<Text>{selectedProject.duration}</Text>
|
|
||||||
</div>
|
|
||||||
<div className={styles.infoItem}>
|
|
||||||
<Text strong>Team Size:</Text>
|
|
||||||
<Text>{selectedProject.teamSize}</Text>
|
|
||||||
</div>
|
|
||||||
<div className={styles.infoItem}>
|
|
||||||
<Text strong>Technologies:</Text>
|
|
||||||
<div className={styles.modalTechnologies}>
|
|
||||||
{selectedProject.technologies.map((tech) => (
|
|
||||||
<Tag key={tech} className={styles.modalTechTag}>
|
|
||||||
{tech}
|
|
||||||
</Tag>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</motion.div>
|
|
||||||
</Modal>
|
|
||||||
)}
|
|
||||||
</AnimatePresence>
|
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
365
src/app/components/ProjectsShowcase/ProjectsShowcaseClient.tsx
Normal file
365
src/app/components/ProjectsShowcase/ProjectsShowcaseClient.tsx
Normal file
@@ -0,0 +1,365 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import {
|
||||||
|
CloseOutlined,
|
||||||
|
EyeOutlined,
|
||||||
|
GithubOutlined,
|
||||||
|
LeftOutlined,
|
||||||
|
LinkOutlined,
|
||||||
|
RightOutlined,
|
||||||
|
} from "@ant-design/icons";
|
||||||
|
import {
|
||||||
|
Badge,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Carousel,
|
||||||
|
Col,
|
||||||
|
Modal,
|
||||||
|
Row,
|
||||||
|
Tag,
|
||||||
|
Typography,
|
||||||
|
} from "antd";
|
||||||
|
import { AnimatePresence, 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;
|
||||||
|
detailedDescription: string;
|
||||||
|
images: string[];
|
||||||
|
liveUrl?: string;
|
||||||
|
githubUrl?: string;
|
||||||
|
features: string[];
|
||||||
|
duration: string;
|
||||||
|
teamSize: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProjectsShowcaseClientProps {
|
||||||
|
projects: Project[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProjectsShowcaseClient: React.FC<ProjectsShowcaseClientProps> = ({
|
||||||
|
projects,
|
||||||
|
}) => {
|
||||||
|
const [currentIndex, setCurrentIndex] = useState(0);
|
||||||
|
const [visibleProjects, setVisibleProjects] = useState<Project[]>([]);
|
||||||
|
const [selectedProject, setSelectedProject] = useState<Project | null>(null);
|
||||||
|
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||||
|
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(
|
||||||
|
projects.slice(currentIndex, currentIndex + projectsPerView)
|
||||||
|
);
|
||||||
|
}, [currentIndex, projectsPerView, projects]);
|
||||||
|
|
||||||
|
const handleNext = async () => {
|
||||||
|
if (currentIndex + projectsPerView < projects.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 },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleProjectClick = (project: Project) => {
|
||||||
|
setSelectedProject(project);
|
||||||
|
setIsModalVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleModalClose = () => {
|
||||||
|
setIsModalVisible(false);
|
||||||
|
setTimeout(() => {
|
||||||
|
setSelectedProject(null);
|
||||||
|
}, 300);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<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
|
||||||
|
onClick={() => handleProjectClick(project)}
|
||||||
|
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, projects.length)} of{" "}
|
||||||
|
{projects.length}
|
||||||
|
</Text>
|
||||||
|
<Button
|
||||||
|
shape="circle"
|
||||||
|
icon={<RightOutlined />}
|
||||||
|
onClick={handleNext}
|
||||||
|
disabled={currentIndex + projectsPerView >= projects.length}
|
||||||
|
className={styles.navButton}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.viewAllContainer}>
|
||||||
|
<Button type="primary" size="large" className={styles.viewAllButton}>
|
||||||
|
View All Projects
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Project Details Modal */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{isModalVisible && selectedProject && (
|
||||||
|
<Modal
|
||||||
|
open={isModalVisible}
|
||||||
|
onCancel={handleModalClose}
|
||||||
|
footer={null}
|
||||||
|
width={1000}
|
||||||
|
className={styles.projectModal}
|
||||||
|
closeIcon={<CloseOutlined className={styles.closeIcon} />}
|
||||||
|
>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.8 }}
|
||||||
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
exit={{ opacity: 0, scale: 0.8 }}
|
||||||
|
transition={{ duration: 0.3 }}
|
||||||
|
className={styles.modalContent}
|
||||||
|
>
|
||||||
|
<div className={styles.modalHeader}>
|
||||||
|
<div className={styles.modalTitleSection}>
|
||||||
|
<Title level={2} className={styles.modalTitle}>
|
||||||
|
{selectedProject.title}
|
||||||
|
</Title>
|
||||||
|
<Tag color="blue" className={styles.modalCategory}>
|
||||||
|
{selectedProject.category}
|
||||||
|
</Tag>
|
||||||
|
</div>
|
||||||
|
<div className={styles.modalActions}>
|
||||||
|
{selectedProject.liveUrl && (
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
icon={<LinkOutlined />}
|
||||||
|
href={selectedProject.liveUrl}
|
||||||
|
target="_blank"
|
||||||
|
className={styles.actionButton}
|
||||||
|
>
|
||||||
|
Live Demo
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{selectedProject.githubUrl && (
|
||||||
|
<Button
|
||||||
|
icon={<GithubOutlined />}
|
||||||
|
href={selectedProject.githubUrl}
|
||||||
|
target="_blank"
|
||||||
|
className={styles.actionButton}
|
||||||
|
>
|
||||||
|
View Code
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.modalBody}>
|
||||||
|
<div className={styles.projectImages}>
|
||||||
|
<Carousel
|
||||||
|
autoplay
|
||||||
|
dots={{ className: styles.carouselDots }}
|
||||||
|
className={styles.imageCarousel}
|
||||||
|
>
|
||||||
|
{selectedProject.images.map((image, index) => (
|
||||||
|
<div key={index} className={styles.carouselItem}>
|
||||||
|
<Image
|
||||||
|
src={image}
|
||||||
|
alt={`${selectedProject.title} - Image ${index + 1}`}
|
||||||
|
width={800}
|
||||||
|
height={500}
|
||||||
|
className={styles.modalImage}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</Carousel>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.projectDetails}>
|
||||||
|
<div className={styles.detailSection}>
|
||||||
|
<Title level={4} className={styles.sectionTitle}>
|
||||||
|
Project Overview
|
||||||
|
</Title>
|
||||||
|
<Paragraph className={styles.projectDescription}>
|
||||||
|
{selectedProject.detailedDescription}
|
||||||
|
</Paragraph>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.detailGrid}>
|
||||||
|
<div className={styles.detailSection}>
|
||||||
|
<Title level={4} className={styles.sectionTitle}>
|
||||||
|
Key Features
|
||||||
|
</Title>
|
||||||
|
<ul className={styles.featuresList}>
|
||||||
|
{selectedProject.features.map((feature, index) => (
|
||||||
|
<motion.li
|
||||||
|
key={index}
|
||||||
|
initial={{ opacity: 0, x: -20 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{ delay: index * 0.1 }}
|
||||||
|
className={styles.featureItem}
|
||||||
|
>
|
||||||
|
{feature}
|
||||||
|
</motion.li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.detailSection}>
|
||||||
|
<Title level={4} className={styles.sectionTitle}>
|
||||||
|
Project Details
|
||||||
|
</Title>
|
||||||
|
<div className={styles.projectInfo}>
|
||||||
|
<div className={styles.infoItem}>
|
||||||
|
<Text strong>Duration:</Text>
|
||||||
|
<Text>{selectedProject.duration}</Text>
|
||||||
|
</div>
|
||||||
|
<div className={styles.infoItem}>
|
||||||
|
<Text strong>Team Size:</Text>
|
||||||
|
<Text>{selectedProject.teamSize}</Text>
|
||||||
|
</div>
|
||||||
|
<div className={styles.infoItem}>
|
||||||
|
<Text strong>Technologies:</Text>
|
||||||
|
<div className={styles.modalTechnologies}>
|
||||||
|
{selectedProject.technologies.map((tech) => (
|
||||||
|
<Tag key={tech} className={styles.modalTechTag}>
|
||||||
|
{tech}
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</Modal>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProjectsShowcaseClient;
|
||||||
32
src/app/contact/layout.tsx
Normal file
32
src/app/contact/layout.tsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Contact Us | Tech Master - Get In Touch for IT Solutions",
|
||||||
|
description: "Contact Tech Master in Dubai for innovative IT solutions, digital transformation, web development, and mobile app development. Start your project today.",
|
||||||
|
keywords: [
|
||||||
|
"contact Tech Master",
|
||||||
|
"Dubai IT company contact",
|
||||||
|
"web development Dubai contact",
|
||||||
|
"digital transformation consultation",
|
||||||
|
"IT solutions contact",
|
||||||
|
"mobile app development Dubai",
|
||||||
|
"enterprise software consultation",
|
||||||
|
"tech agency Dubai contact"
|
||||||
|
],
|
||||||
|
openGraph: {
|
||||||
|
title: "Contact Us | Tech Master - Get In Touch for IT Solutions",
|
||||||
|
description: "Contact Tech Master in Dubai for innovative IT solutions, digital transformation, and mobile app development.",
|
||||||
|
url: "https://tech-masters.guru/contact",
|
||||||
|
},
|
||||||
|
alternates: {
|
||||||
|
canonical: "/contact",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function ContactLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
11
src/app/contact/page.tsx
Normal file
11
src/app/contact/page.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import ContactSection from "../components/Contact/Contact";
|
||||||
|
|
||||||
|
export default function ContactPage() {
|
||||||
|
return (
|
||||||
|
<main className="pt-20">
|
||||||
|
<ContactSection />
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -17,7 +17,78 @@ const inter = Inter({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Tech Master | Dubai To Stars",
|
title: "Tech Master | Dubai To Stars - Award-Winning IT Solutions",
|
||||||
|
description: "Tech Master is an award-winning Dubai-based technology agency specializing in digital transformation, web development, mobile apps, AI solutions, and enterprise software. From zero to hero, we create cutting-edge digital experiences for ambitious businesses.",
|
||||||
|
keywords: [
|
||||||
|
"Dubai IT solutions",
|
||||||
|
"digital transformation",
|
||||||
|
"web development Dubai",
|
||||||
|
"mobile app development",
|
||||||
|
"AI solutions",
|
||||||
|
"enterprise software",
|
||||||
|
"ERP systems",
|
||||||
|
"e-commerce development",
|
||||||
|
"financial solutions",
|
||||||
|
"legal software",
|
||||||
|
"business intelligence",
|
||||||
|
"cloud migration",
|
||||||
|
"cybersecurity",
|
||||||
|
"blockchain development",
|
||||||
|
"IoT solutions",
|
||||||
|
"tech agency Dubai",
|
||||||
|
"software development UAE"
|
||||||
|
],
|
||||||
|
authors: [{ name: "Tech Master" }],
|
||||||
|
creator: "Tech Master",
|
||||||
|
publisher: "Tech Master",
|
||||||
|
formatDetection: {
|
||||||
|
email: false,
|
||||||
|
address: false,
|
||||||
|
telephone: false,
|
||||||
|
},
|
||||||
|
metadataBase: new URL("https://tech-masters.guru"),
|
||||||
|
alternates: {
|
||||||
|
canonical: "/",
|
||||||
|
},
|
||||||
|
openGraph: {
|
||||||
|
title: "Tech Master | Dubai To Stars - Award-Winning IT Solutions",
|
||||||
|
description: "Award-winning Dubai-based technology agency specializing in digital transformation, web development, mobile apps, AI solutions, and enterprise software.",
|
||||||
|
url: "https://tech-masters.guru",
|
||||||
|
siteName: "Tech Master",
|
||||||
|
images: [
|
||||||
|
{
|
||||||
|
url: "https://tech-masters.guru/og-image.jpg",
|
||||||
|
width: 1200,
|
||||||
|
height: 630,
|
||||||
|
alt: "Tech Master - Dubai To Stars",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
locale: "en_US",
|
||||||
|
type: "website",
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
card: "summary_large_image",
|
||||||
|
title: "Tech Master | Dubai To Stars - Award-Winning IT Solutions",
|
||||||
|
description: "Award-winning Dubai-based technology agency specializing in digital transformation and innovative IT solutions.",
|
||||||
|
images: ["https://tech-masters.guru/twitter-image.jpg"],
|
||||||
|
creator: "@techmasterdubai",
|
||||||
|
},
|
||||||
|
robots: {
|
||||||
|
index: true,
|
||||||
|
follow: true,
|
||||||
|
googleBot: {
|
||||||
|
index: true,
|
||||||
|
follow: true,
|
||||||
|
"max-video-preview": -1,
|
||||||
|
"max-image-preview": "large",
|
||||||
|
"max-snippet": -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
verification: {
|
||||||
|
google: "your-google-verification-code",
|
||||||
|
yandex: "your-yandex-verification-code",
|
||||||
|
yahoo: "your-yahoo-verification-code",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
@@ -37,7 +108,36 @@ export default function RootLayout({
|
|||||||
src="https://threejs.org/examples/js/libs/stats.min.js"
|
src="https://threejs.org/examples/js/libs/stats.min.js"
|
||||||
async
|
async
|
||||||
></script>
|
></script>
|
||||||
{/* Orbitron Font */}
|
|
||||||
|
{/* Structured Data */}
|
||||||
|
<script
|
||||||
|
type="application/ld+json"
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: JSON.stringify({
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "Organization",
|
||||||
|
"name": "Tech Master",
|
||||||
|
"url": "https://tech-masters.guru",
|
||||||
|
"logo": "https://tech-masters.guru/logo.png",
|
||||||
|
"description": "Award-winning Dubai-based technology agency specializing in digital transformation and innovative IT solutions.",
|
||||||
|
"address": {
|
||||||
|
"@type": "PostalAddress",
|
||||||
|
"addressLocality": "Dubai",
|
||||||
|
"addressCountry": "UAE"
|
||||||
|
},
|
||||||
|
"contactPoint": {
|
||||||
|
"@type": "ContactPoint",
|
||||||
|
"telephone": "+971-XX-XXX-XXXX",
|
||||||
|
"contactType": "customer service"
|
||||||
|
},
|
||||||
|
"sameAs": [
|
||||||
|
"https://linkedin.com/company/tech-master",
|
||||||
|
"https://twitter.com/techmasterdubai",
|
||||||
|
"https://facebook.com/techmasterdubai"
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</head>
|
</head>
|
||||||
<body
|
<body
|
||||||
className={`${inter.className} bg-gradient-to-br from-[#0F0525] to-[#2A0B45]`}
|
className={`${inter.className} bg-gradient-to-br from-[#0F0525] to-[#2A0B45]`}
|
||||||
|
|||||||
@@ -61,11 +61,25 @@ export default function Home() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<main className={styles.main}>
|
<main className={styles.main}>
|
||||||
<HeroSection />
|
<section id="home">
|
||||||
<ServicesSection userPreferences={userPreferences} />
|
<HeroSection />
|
||||||
<ProjectsShowcase />
|
</section>
|
||||||
<TestimonialsSection />
|
|
||||||
<ContactSection />
|
<section id="services">
|
||||||
|
<ServicesSection userPreferences={userPreferences} />
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="projects">
|
||||||
|
<ProjectsShowcase />
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="testimonials">
|
||||||
|
<TestimonialsSection />
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="contact">
|
||||||
|
<ContactSection />
|
||||||
|
</section>
|
||||||
</main>
|
</main>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
34
src/app/projects/layout.tsx
Normal file
34
src/app/projects/layout.tsx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Our Projects | Tech Master - Portfolio of Digital Solutions",
|
||||||
|
description: "Explore our portfolio of successful projects including ERP systems, e-commerce platforms, payment solutions, legal software, and business intelligence dashboards developed in Dubai.",
|
||||||
|
keywords: [
|
||||||
|
"portfolio projects",
|
||||||
|
"ERP systems Dubai",
|
||||||
|
"e-commerce development",
|
||||||
|
"payment platforms",
|
||||||
|
"legal software",
|
||||||
|
"business intelligence",
|
||||||
|
"web applications",
|
||||||
|
"mobile apps",
|
||||||
|
"enterprise software",
|
||||||
|
"fintech solutions"
|
||||||
|
],
|
||||||
|
openGraph: {
|
||||||
|
title: "Our Projects | Tech Master - Portfolio of Digital Solutions",
|
||||||
|
description: "Portfolio of successful projects including ERP systems, e-commerce platforms, payment solutions, and business intelligence dashboards.",
|
||||||
|
url: "https://tech-masters.guru/projects",
|
||||||
|
},
|
||||||
|
alternates: {
|
||||||
|
canonical: "/projects",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function ProjectsLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
9
src/app/projects/page.tsx
Normal file
9
src/app/projects/page.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import ProjectsShowcase from "../components/ProjectsShowcase/ProjectsShowcase";
|
||||||
|
|
||||||
|
export default function ProjectsPage() {
|
||||||
|
return (
|
||||||
|
<main className="pt-20">
|
||||||
|
<ProjectsShowcase />
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
12
src/app/robots.ts
Normal file
12
src/app/robots.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { MetadataRoute } from 'next'
|
||||||
|
|
||||||
|
export default function robots(): MetadataRoute.Robots {
|
||||||
|
return {
|
||||||
|
rules: {
|
||||||
|
userAgent: '*',
|
||||||
|
allow: '/',
|
||||||
|
disallow: '/private/',
|
||||||
|
},
|
||||||
|
sitemap: 'https://tech-masters.guru/sitemap.xml',
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/app/services/layout.tsx
Normal file
33
src/app/services/layout.tsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Our Services | Tech Master - Digital Transformation & IT Solutions",
|
||||||
|
description: "Explore our comprehensive IT services including web development, mobile apps, AI solutions, ERP systems, e-commerce platforms, and digital transformation services in Dubai.",
|
||||||
|
keywords: [
|
||||||
|
"web development Dubai",
|
||||||
|
"mobile app development",
|
||||||
|
"AI solutions",
|
||||||
|
"ERP systems",
|
||||||
|
"e-commerce development",
|
||||||
|
"digital transformation",
|
||||||
|
"cloud migration",
|
||||||
|
"cybersecurity services",
|
||||||
|
"IT consulting Dubai"
|
||||||
|
],
|
||||||
|
openGraph: {
|
||||||
|
title: "Our Services | Tech Master - Digital Transformation & IT Solutions",
|
||||||
|
description: "Comprehensive IT services including web development, mobile apps, AI solutions, ERP systems, and digital transformation in Dubai.",
|
||||||
|
url: "https://tech-masters.guru/services",
|
||||||
|
},
|
||||||
|
alternates: {
|
||||||
|
canonical: "/services",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function ServicesLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
11
src/app/services/page.tsx
Normal file
11
src/app/services/page.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import ServicesSection from "../components/Services/Services";
|
||||||
|
|
||||||
|
export default function ServicesPage() {
|
||||||
|
return (
|
||||||
|
<main className="pt-20">
|
||||||
|
<ServicesSection userPreferences={[]} />
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
44
src/app/sitemap.ts
Normal file
44
src/app/sitemap.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { MetadataRoute } from 'next'
|
||||||
|
|
||||||
|
export default function sitemap(): MetadataRoute.Sitemap {
|
||||||
|
const baseUrl = 'https://tech-masters.guru'
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
url: baseUrl,
|
||||||
|
lastModified: new Date(),
|
||||||
|
changeFrequency: 'weekly',
|
||||||
|
priority: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: `${baseUrl}/about`,
|
||||||
|
lastModified: new Date(),
|
||||||
|
changeFrequency: 'monthly',
|
||||||
|
priority: 0.8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: `${baseUrl}/services`,
|
||||||
|
lastModified: new Date(),
|
||||||
|
changeFrequency: 'monthly',
|
||||||
|
priority: 0.8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: `${baseUrl}/projects`,
|
||||||
|
lastModified: new Date(),
|
||||||
|
changeFrequency: 'weekly',
|
||||||
|
priority: 0.9,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: `${baseUrl}/testimonials`,
|
||||||
|
lastModified: new Date(),
|
||||||
|
changeFrequency: 'monthly',
|
||||||
|
priority: 0.7,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: `${baseUrl}/contact`,
|
||||||
|
lastModified: new Date(),
|
||||||
|
changeFrequency: 'monthly',
|
||||||
|
priority: 0.8,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
32
src/app/testimonials/layout.tsx
Normal file
32
src/app/testimonials/layout.tsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Client Testimonials | Tech Master - What Our Clients Say",
|
||||||
|
description: "Read testimonials from our satisfied clients in Dubai. Discover how Tech Master has helped businesses achieve digital transformation and success through innovative IT solutions.",
|
||||||
|
keywords: [
|
||||||
|
"client testimonials",
|
||||||
|
"customer reviews",
|
||||||
|
"Dubai IT company reviews",
|
||||||
|
"digital transformation success",
|
||||||
|
"IT solutions testimonials",
|
||||||
|
"web development reviews",
|
||||||
|
"mobile app development feedback",
|
||||||
|
"enterprise software testimonials"
|
||||||
|
],
|
||||||
|
openGraph: {
|
||||||
|
title: "Client Testimonials | Tech Master - What Our Clients Say",
|
||||||
|
description: "Read testimonials from our satisfied clients in Dubai. Discover how Tech Master has helped businesses achieve digital transformation.",
|
||||||
|
url: "https://tech-masters.guru/testimonials",
|
||||||
|
},
|
||||||
|
alternates: {
|
||||||
|
canonical: "/testimonials",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function TestimonialsLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
11
src/app/testimonials/page.tsx
Normal file
11
src/app/testimonials/page.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import TestimonialsSection from "../components/Testimonials/Testimonials";
|
||||||
|
|
||||||
|
export default function TestimonialsPage() {
|
||||||
|
return (
|
||||||
|
<main className="pt-20">
|
||||||
|
<TestimonialsSection />
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user