Compare commits
5 Commits
3bc52d60c3
...
8f05d06fb9
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f05d06fb9 | |||
| 9548694f13 | |||
| 2c84cbd1ca | |||
| 323a5665fe | |||
| adcab9eb3c |
@@ -7,6 +7,10 @@ const nextConfig: NextConfig = {
|
|||||||
protocol: "https",
|
protocol: "https",
|
||||||
hostname: "techmasters.space",
|
hostname: "techmasters.space",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
protocol: "https",
|
||||||
|
hostname: "tech-masters.guru",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { BellOutlined, UserOutlined } from "@ant-design/icons";
|
|||||||
import { Avatar, Button, Menu, MenuProps, Typography } from "antd";
|
import { Avatar, Button, Menu, MenuProps, Typography } from "antd";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import { usePathname } from "next/navigation";
|
||||||
|
import { useEffect, useMemo } from "react";
|
||||||
import styles from "./Header.module.css";
|
import styles from "./Header.module.css";
|
||||||
|
|
||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
@@ -31,7 +33,41 @@ const items: MenuProps['items'] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const TITLE_SUFFIX = "Tech Masters";
|
||||||
|
|
||||||
const Header = () => {
|
const Header = () => {
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
const selectedKey = useMemo(() => {
|
||||||
|
if (!pathname || pathname === "/") return "home";
|
||||||
|
const key = pathname.split("/")[1];
|
||||||
|
return key || "home";
|
||||||
|
}, [pathname]);
|
||||||
|
|
||||||
|
const pageTitle = useMemo(() => {
|
||||||
|
switch (selectedKey) {
|
||||||
|
case "home":
|
||||||
|
return "Home";
|
||||||
|
case "services":
|
||||||
|
return "Services";
|
||||||
|
case "projects":
|
||||||
|
return "Projects";
|
||||||
|
case "about":
|
||||||
|
return "About";
|
||||||
|
case "contact":
|
||||||
|
return "Contact";
|
||||||
|
case "testimonials":
|
||||||
|
return "Testimonials";
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, [selectedKey]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!pageTitle) return;
|
||||||
|
document.title = `${pageTitle} | ${TITLE_SUFFIX}`;
|
||||||
|
}, [pageTitle]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className={styles.header}>
|
<header className={styles.header}>
|
||||||
<div className={styles.headerContainer}>
|
<div className={styles.headerContainer}>
|
||||||
@@ -68,7 +104,7 @@ const Header = () => {
|
|||||||
mode="horizontal"
|
mode="horizontal"
|
||||||
items={items}
|
items={items}
|
||||||
className={styles.menu}
|
className={styles.menu}
|
||||||
selectedKeys={['home']}
|
selectedKeys={[selectedKey]}
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ const PreferencesSelector: React.FC<PreferencesSelectorProps> = ({
|
|||||||
onComplete,
|
onComplete,
|
||||||
}) => {
|
}) => {
|
||||||
const [selectedPreferences, setSelectedPreferences] = useState<string[]>([]);
|
const [selectedPreferences, setSelectedPreferences] = useState<string[]>([]);
|
||||||
|
const [messageApi, contextHolder] = message.useMessage();
|
||||||
|
|
||||||
const handleTogglePreference = (id: string) => {
|
const handleTogglePreference = (id: string) => {
|
||||||
setSelectedPreferences((prev) =>
|
setSelectedPreferences((prev) =>
|
||||||
@@ -59,7 +60,7 @@ const PreferencesSelector: React.FC<PreferencesSelectorProps> = ({
|
|||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
if (selectedPreferences.length === 0) {
|
if (selectedPreferences.length === 0) {
|
||||||
message.warning("Please select at least one preference");
|
messageApi.warning("Please select at least one preference");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +69,7 @@ const PreferencesSelector: React.FC<PreferencesSelectorProps> = ({
|
|||||||
"userPreferences",
|
"userPreferences",
|
||||||
JSON.stringify(selectedPreferences)
|
JSON.stringify(selectedPreferences)
|
||||||
);
|
);
|
||||||
message.success("Preferences saved successfully!");
|
messageApi.success("Preferences saved successfully!");
|
||||||
onComplete();
|
onComplete();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -79,6 +80,7 @@ const PreferencesSelector: React.FC<PreferencesSelectorProps> = ({
|
|||||||
animate={{ opacity: 1 }}
|
animate={{ opacity: 1 }}
|
||||||
transition={{ duration: 0.5 }}
|
transition={{ duration: 0.5 }}
|
||||||
>
|
>
|
||||||
|
{contextHolder}
|
||||||
<Card className={styles.card}>
|
<Card className={styles.card}>
|
||||||
<Title level={2}>Welcome to Tech Master</Title>
|
<Title level={2}>Welcome to Tech Master</Title>
|
||||||
<Text>
|
<Text>
|
||||||
@@ -86,7 +88,7 @@ const PreferencesSelector: React.FC<PreferencesSelectorProps> = ({
|
|||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
direction="vertical"
|
orientation="vertical"
|
||||||
size="large"
|
size="large"
|
||||||
className={styles.optionsContainer}
|
className={styles.optionsContainer}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
background: linear-gradient(135deg, #42475c 0%, #20222f 100%);
|
background: linear-gradient(135deg, #42475c 0%, #20222f 100%);
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
@@ -21,6 +22,8 @@
|
|||||||
background: rgba(255, 255, 255, 0.9);
|
background: rgba(255, 255, 255, 0.9);
|
||||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
|
max-height: calc(100vh - 32px);
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.optionsContainer {
|
.optionsContainer {
|
||||||
@@ -56,3 +59,39 @@
|
|||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
box-shadow: 0 6px 16px rgba(24, 144, 255, 0.2);
|
box-shadow: 0 6px 16px rgba(24, 144, 255, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.container {
|
||||||
|
align-items: flex-start;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 14px;
|
||||||
|
max-height: calc(100vh - 24px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.optionsContainer {
|
||||||
|
margin: 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.optionCard {
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.continueButton {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
height: 44px;
|
||||||
|
border-radius: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 380px) {
|
||||||
|
.card {
|
||||||
|
padding: 0.85rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,13 +22,14 @@ const { TextArea } = Input;
|
|||||||
export default function ContactPage() {
|
export default function ContactPage() {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [submitting, setSubmitting] = useState(false);
|
const [submitting, setSubmitting] = useState(false);
|
||||||
|
const [messageApi, contextHolder] = message.useMessage();
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
|
|
||||||
// Simulate API call
|
// Simulate API call
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
message.success("Your message has been sent successfully!");
|
messageApi.success("Your message has been sent successfully!");
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
}, 1500);
|
}, 1500);
|
||||||
@@ -55,6 +56,7 @@ export default function ContactPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<main className={styles.main}>
|
<main className={styles.main}>
|
||||||
|
{contextHolder}
|
||||||
{/* Hero Section */}
|
{/* Hero Section */}
|
||||||
<section className={styles.heroSection}>
|
<section className={styles.heroSection}>
|
||||||
<div className={styles.heroBackground}>
|
<div className={styles.heroBackground}>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
ProjectOutlined,
|
ProjectOutlined,
|
||||||
RocketOutlined,
|
RocketOutlined,
|
||||||
StarOutlined,
|
StarOutlined,
|
||||||
TeamOutlined
|
TeamOutlined,
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import { Card, Col, Row, Statistic, Typography } from "antd";
|
import { Card, Col, Row, Statistic, Typography } from "antd";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
@@ -22,21 +22,26 @@ import styles from "./page.module.css";
|
|||||||
const { Title, Paragraph } = Typography;
|
const { Title, Paragraph } = Typography;
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const [userPreferences, setUserPreferences] = useState<string[]>(() => {
|
// Keep the initial render identical between server and client to avoid hydration mismatches.
|
||||||
try {
|
// We'll read localStorage after mount.
|
||||||
const storedPreferences = localStorage.getItem("userPreferences");
|
const [, setUserPreferences] = useState<string[]>([]);
|
||||||
return storedPreferences ? JSON.parse(storedPreferences) : [];
|
const [showPreferences, setShowPreferences] = useState(true);
|
||||||
} catch {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const [showPreferences, setShowPreferences] = useState(
|
|
||||||
() => userPreferences.length === 0,
|
|
||||||
);
|
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// Reading localStorage can only happen on the client; do it after mount.
|
||||||
|
try {
|
||||||
|
const storedPreferences = localStorage.getItem("userPreferences");
|
||||||
|
if (storedPreferences) {
|
||||||
|
/* eslint-disable react-hooks/set-state-in-effect */
|
||||||
|
setUserPreferences(JSON.parse(storedPreferences));
|
||||||
|
setShowPreferences(false);
|
||||||
|
/* eslint-enable react-hooks/set-state-in-effect */
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignore invalid JSON / access errors
|
||||||
|
}
|
||||||
|
|
||||||
// Simulate loading of resources
|
// Simulate loading of resources
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -61,7 +66,7 @@ export default function Home() {
|
|||||||
<div className={styles.loaderOrb2}></div>
|
<div className={styles.loaderOrb2}></div>
|
||||||
<div className={styles.loaderOrb3}></div>
|
<div className={styles.loaderOrb3}></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.loaderContent}>
|
<div className={styles.loaderContent}>
|
||||||
<div className={styles.logoContainer}>
|
<div className={styles.logoContainer}>
|
||||||
<div className={styles.logoIcon}>
|
<div className={styles.logoIcon}>
|
||||||
@@ -72,7 +77,7 @@ export default function Home() {
|
|||||||
<span className={styles.logoSubtitle}>Masters</span>
|
<span className={styles.logoSubtitle}>Masters</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.loaderAnimation}>
|
<div className={styles.loaderAnimation}>
|
||||||
<div className={styles.loaderDots}>
|
<div className={styles.loaderDots}>
|
||||||
<div className={styles.dot}></div>
|
<div className={styles.dot}></div>
|
||||||
@@ -80,7 +85,7 @@ export default function Home() {
|
|||||||
<div className={styles.dot}></div>
|
<div className={styles.dot}></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.loaderText}>
|
<div className={styles.loaderText}>
|
||||||
<Title level={4} className={styles.loaderTitle}>
|
<Title level={4} className={styles.loaderTitle}>
|
||||||
Preparing Your Experience
|
Preparing Your Experience
|
||||||
@@ -113,10 +118,11 @@ export default function Home() {
|
|||||||
Our Services
|
Our Services
|
||||||
</Title>
|
</Title>
|
||||||
<Paragraph className={styles.sectionSubtitle}>
|
<Paragraph className={styles.sectionSubtitle}>
|
||||||
We offer comprehensive solutions to transform your digital presence and drive business growth
|
We offer comprehensive solutions to transform your digital
|
||||||
|
presence and drive business growth
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Row gutter={[32, 32]} className={styles.servicesGrid}>
|
<Row gutter={[32, 32]} className={styles.servicesGrid}>
|
||||||
<Col xs={24} sm={12} lg={8}>
|
<Col xs={24} sm={12} lg={8}>
|
||||||
<Card className={styles.serviceCard} hoverable>
|
<Card className={styles.serviceCard} hoverable>
|
||||||
@@ -127,7 +133,8 @@ export default function Home() {
|
|||||||
Web Development
|
Web Development
|
||||||
</Title>
|
</Title>
|
||||||
<Paragraph className={styles.serviceDescription}>
|
<Paragraph className={styles.serviceDescription}>
|
||||||
Custom web applications built with modern technologies and best practices for optimal performance and user experience.
|
Custom web applications built with modern technologies and
|
||||||
|
best practices for optimal performance and user experience.
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
<ul className={styles.serviceFeatures}>
|
<ul className={styles.serviceFeatures}>
|
||||||
<li>Responsive Design</li>
|
<li>Responsive Design</li>
|
||||||
@@ -137,7 +144,7 @@ export default function Home() {
|
|||||||
</ul>
|
</ul>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col xs={24} sm={12} lg={8}>
|
<Col xs={24} sm={12} lg={8}>
|
||||||
<Card className={styles.serviceCard} hoverable>
|
<Card className={styles.serviceCard} hoverable>
|
||||||
<div className={styles.serviceIcon}>
|
<div className={styles.serviceIcon}>
|
||||||
@@ -147,7 +154,8 @@ export default function Home() {
|
|||||||
Mobile Development
|
Mobile Development
|
||||||
</Title>
|
</Title>
|
||||||
<Paragraph className={styles.serviceDescription}>
|
<Paragraph className={styles.serviceDescription}>
|
||||||
Native and cross-platform mobile applications that deliver exceptional user experiences across all devices.
|
Native and cross-platform mobile applications that deliver
|
||||||
|
exceptional user experiences across all devices.
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
<ul className={styles.serviceFeatures}>
|
<ul className={styles.serviceFeatures}>
|
||||||
<li>iOS & Android Apps</li>
|
<li>iOS & Android Apps</li>
|
||||||
@@ -157,7 +165,7 @@ export default function Home() {
|
|||||||
</ul>
|
</ul>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col xs={24} sm={12} lg={8}>
|
<Col xs={24} sm={12} lg={8}>
|
||||||
<Card className={styles.serviceCard} hoverable>
|
<Card className={styles.serviceCard} hoverable>
|
||||||
<div className={styles.serviceIcon}>
|
<div className={styles.serviceIcon}>
|
||||||
@@ -167,7 +175,8 @@ export default function Home() {
|
|||||||
UI/UX Design
|
UI/UX Design
|
||||||
</Title>
|
</Title>
|
||||||
<Paragraph className={styles.serviceDescription}>
|
<Paragraph className={styles.serviceDescription}>
|
||||||
User-centered design solutions that create intuitive, engaging, and conversion-focused digital experiences.
|
User-centered design solutions that create intuitive,
|
||||||
|
engaging, and conversion-focused digital experiences.
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
<ul className={styles.serviceFeatures}>
|
<ul className={styles.serviceFeatures}>
|
||||||
<li>User Research</li>
|
<li>User Research</li>
|
||||||
@@ -189,10 +198,11 @@ export default function Home() {
|
|||||||
Our Impact
|
Our Impact
|
||||||
</Title>
|
</Title>
|
||||||
<Paragraph className={styles.sectionSubtitle}>
|
<Paragraph className={styles.sectionSubtitle}>
|
||||||
Numbers that speak for themselves - our commitment to excellence in every project
|
Numbers that speak for themselves - our commitment to excellence
|
||||||
|
in every project
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Row gutter={[48, 32]} className={styles.statsGrid}>
|
<Row gutter={[48, 32]} className={styles.statsGrid}>
|
||||||
<Col xs={12} sm={6}>
|
<Col xs={12} sm={6}>
|
||||||
<div className={styles.statCard}>
|
<div className={styles.statCard}>
|
||||||
@@ -207,7 +217,7 @@ export default function Home() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col xs={12} sm={6}>
|
<Col xs={12} sm={6}>
|
||||||
<div className={styles.statCard}>
|
<div className={styles.statCard}>
|
||||||
<div className={styles.statIcon}>
|
<div className={styles.statIcon}>
|
||||||
@@ -221,7 +231,7 @@ export default function Home() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col xs={12} sm={6}>
|
<Col xs={12} sm={6}>
|
||||||
<div className={styles.statCard}>
|
<div className={styles.statCard}>
|
||||||
<div className={styles.statIcon}>
|
<div className={styles.statIcon}>
|
||||||
@@ -236,7 +246,7 @@ export default function Home() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col xs={12} sm={6}>
|
<Col xs={12} sm={6}>
|
||||||
<div className={styles.statCard}>
|
<div className={styles.statCard}>
|
||||||
<div className={styles.statIcon}>
|
<div className={styles.statIcon}>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
EyeOutlined,
|
EyeOutlined,
|
||||||
LinkOutlined,
|
LinkOutlined,
|
||||||
RocketOutlined,
|
RocketOutlined,
|
||||||
UserOutlined
|
UserOutlined,
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import {
|
import {
|
||||||
Badge,
|
Badge,
|
||||||
@@ -403,8 +403,8 @@ export default function ProjectsPage() {
|
|||||||
Featured <span className={styles.gradientText}>Work</span>
|
Featured <span className={styles.gradientText}>Work</span>
|
||||||
</Title>
|
</Title>
|
||||||
<Paragraph className={styles.projectsSubtitle}>
|
<Paragraph className={styles.projectsSubtitle}>
|
||||||
Discover our latest projects and see how we've helped businesses
|
Discover our latest projects and see how we've helped
|
||||||
achieve their digital transformation goals.
|
businesses achieve their digital transformation goals.
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user