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

41
.gitignore vendored Normal file
View File

@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

5
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"cSpell.words": [
"hoverable"
]
}

36
README.md Normal file
View File

@@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.

16
eslint.config.mjs Normal file
View File

@@ -0,0 +1,16 @@
import { dirname } from "path";
import { fileURLToPath } from "url";
import { FlatCompat } from "@eslint/eslintrc";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
});
const eslintConfig = [
...compat.extends("next/core-web-vitals", "next/typescript"),
];
export default eslintConfig;

7
next.config.ts Normal file
View File

@@ -0,0 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
};
export default nextConfig;

27
package.json Normal file
View File

@@ -0,0 +1,27 @@
{
"name": "antd-demo",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"antd": "^5.24.6",
"framer-motion": "^12.6.3",
"next": "15.2.4",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "15.2.4",
"typescript": "^5"
}
}

1
public/file.svg Normal file
View File

@@ -0,0 +1 @@
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 391 B

1
public/globe.svg Normal file
View File

@@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

1
public/next.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

1
public/vercel.svg Normal file
View File

@@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 128 B

1
public/window.svg Normal file
View File

@@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>

After

Width:  |  Height:  |  Size: 385 B

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

27
tsconfig.json Normal file
View File

@@ -0,0 +1,27 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

3298
yarn.lock Normal file

File diff suppressed because it is too large Load Diff