diff --git a/bun.lock b/bun.lock
index ace049f..a5dc5d9 100644
--- a/bun.lock
+++ b/bun.lock
@@ -11,12 +11,16 @@
"@fortawesome/free-regular-svg-icons": "^6.7.2",
"@fortawesome/free-solid-svg-icons": "^6.7.2",
"@fortawesome/react-fontawesome": "^0.2.6",
+ "@radix-ui/react-slot": "^1.3.0",
"@reduxjs/toolkit": "^2.12.0",
"clsx": "^2.1.1",
"date-fns": "^4.4.0",
+ "framer-motion": "^12.42.2",
+ "lucide-react": "^1.25.0",
"react": "^19.2.7",
"react-confetti-explosion": "^3.0.3",
"react-dom": "^19.2.7",
+ "react-helmet-async": "^3.0.0",
"react-redux": "^9.3.0",
"react-router-dom": "^7.18.1",
"tailwind-merge": "^3.6.0",
@@ -197,6 +201,10 @@
"@pkgr/core": ["@pkgr/core@0.3.6", "", {}, "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA=="],
+ "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA=="],
+
+ "@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA=="],
+
"@reduxjs/toolkit": ["@reduxjs/toolkit@2.12.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@standard-schema/utils": "^0.3.0", "immer": "^11.0.0", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "optionalPeers": ["react", "react-redux"] }, "sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw=="],
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="],
@@ -511,6 +519,8 @@
"flatted": ["flatted@3.4.2", "", {}, "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA=="],
+ "framer-motion": ["framer-motion@12.42.2", "", { "dependencies": { "motion-dom": "^12.42.2", "motion-utils": "^12.39.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-5XY9luDiu0oHfHBjpDthFMh0ES+122w6p/papSJBweMkO8Sn+PW2QaEgRblQBpWFnuvZS5qvarpt/hO2pjGmnw=="],
+
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
@@ -531,6 +541,8 @@
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
+ "invariant": ["invariant@2.2.4", "", { "dependencies": { "loose-envify": "^1.0.0" } }, "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA=="],
+
"is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="],
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
@@ -601,6 +613,8 @@
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
+ "lucide-react": ["lucide-react@1.25.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-/mdJTRbiwcLOQ1NZZK1amZF9rIZyvO18D6r9TngE6TG1NmqHgFuT4eE7Xrkm9UsXMbBJD1NlfwHVltCDWHrOTw=="],
+
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
@@ -611,6 +625,10 @@
"mlly": ["mlly@1.8.2", "", { "dependencies": { "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.3" } }, "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA=="],
+ "motion-dom": ["motion-dom@12.42.2", "", { "dependencies": { "motion-utils": "^12.39.0" } }, "sha512-5gIMWLp/PycBtJRJWRgjxke5n8dlvkSn2DrYW+tr3XcqAZY1xZh6BJyooJXCM8wdfM7wfMjkBJNLge1CKPUIRA=="],
+
+ "motion-utils": ["motion-utils@12.39.0", "", {}, "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ=="],
+
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"nanoid": ["nanoid@3.3.15", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA=="],
@@ -669,6 +687,10 @@
"react-dom": ["react-dom@19.2.7", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.7" } }, "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ=="],
+ "react-fast-compare": ["react-fast-compare@3.2.2", "", {}, "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="],
+
+ "react-helmet-async": ["react-helmet-async@3.0.0", "", { "dependencies": { "invariant": "^2.2.4", "react-fast-compare": "^3.2.2", "shallowequal": "^1.1.0" }, "peerDependencies": { "react": "^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-nA3IEZfXiclgrz4KLxAhqJqIfFDuvzQwlKwpdmzZIuC1KNSghDEIXmyU0TKtbM+NafnkICcwx8CECFrZ/sL/1w=="],
+
"react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
"react-redux": ["react-redux@9.3.0", "", { "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "@types/react": "^18.2.25 || ^19", "react": "^18.0 || ^19", "redux": "^5.0.0" }, "optionalPeers": ["@types/react", "redux"] }, "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g=="],
@@ -699,6 +721,8 @@
"set-cookie-parser": ["set-cookie-parser@2.7.2", "", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="],
+ "shallowequal": ["shallowequal@1.1.0", "", {}, "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="],
+
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
diff --git a/index.html b/index.html
index 5b0d039..a26c04a 100644
--- a/index.html
+++ b/index.html
@@ -2,13 +2,17 @@
-
-
- Lakshmikanta Patra | FrontendFixer [♥]
+
+
+
+
+
+
+
-
+
diff --git a/package.json b/package.json
index ab777a0..1a9291f 100644
--- a/package.json
+++ b/package.json
@@ -21,12 +21,16 @@
"@fortawesome/free-regular-svg-icons": "^6.7.2",
"@fortawesome/free-solid-svg-icons": "^6.7.2",
"@fortawesome/react-fontawesome": "^0.2.6",
+ "@radix-ui/react-slot": "^1.3.0",
"@reduxjs/toolkit": "^2.12.0",
"clsx": "^2.1.1",
"date-fns": "^4.4.0",
+ "framer-motion": "^12.42.2",
+ "lucide-react": "^1.25.0",
"react": "^19.2.7",
"react-confetti-explosion": "^3.0.3",
"react-dom": "^19.2.7",
+ "react-helmet-async": "^3.0.0",
"react-redux": "^9.3.0",
"react-router-dom": "^7.18.1",
"tailwind-merge": "^3.6.0",
diff --git a/public/Lakshmikanta.pdf b/public/Lakshmikanta.pdf
deleted file mode 100644
index cdffd35..0000000
Binary files a/public/Lakshmikanta.pdf and /dev/null differ
diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png
new file mode 100644
index 0000000..f459fcc
Binary files /dev/null and b/public/android-chrome-192x192.png differ
diff --git a/public/android-chrome-512x512.png b/public/android-chrome-512x512.png
new file mode 100644
index 0000000..f71def1
Binary files /dev/null and b/public/android-chrome-512x512.png differ
diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png
new file mode 100644
index 0000000..affa9a8
Binary files /dev/null and b/public/apple-touch-icon.png differ
diff --git a/public/demo.webp b/public/demo.webp
deleted file mode 100644
index 7d791df..0000000
Binary files a/public/demo.webp and /dev/null differ
diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png
new file mode 100644
index 0000000..d5a15e3
Binary files /dev/null and b/public/favicon-16x16.png differ
diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png
new file mode 100644
index 0000000..9624341
Binary files /dev/null and b/public/favicon-32x32.png differ
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000..ccad1ed
Binary files /dev/null and b/public/favicon.ico differ
diff --git a/public/og-image.png b/public/og-image.png
new file mode 100644
index 0000000..1922960
Binary files /dev/null and b/public/og-image.png differ
diff --git a/public/robots.txt b/public/robots.txt
new file mode 100644
index 0000000..4f20ecd
--- /dev/null
+++ b/public/robots.txt
@@ -0,0 +1,4 @@
+User-agent: *
+Allow: /
+
+Sitemap: https://frontendfixer.dev/sitemap.xml
diff --git a/public/site.webmanifest b/public/site.webmanifest
new file mode 100644
index 0000000..7d8262d
--- /dev/null
+++ b/public/site.webmanifest
@@ -0,0 +1,21 @@
+{
+ "name": "FrontendFixer",
+ "short_name": "FrontendFixer",
+ "description": "Full-Stack Developer for SaaS & MVPs",
+ "start_url": "/",
+ "display": "standalone",
+ "background_color": "#09090B",
+ "theme_color": "#14b8a6",
+ "icons": [
+ {
+ "src": "/android-chrome-192x192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "/android-chrome-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ]
+}
diff --git a/public/sitemap.xml b/public/sitemap.xml
new file mode 100644
index 0000000..af18137
--- /dev/null
+++ b/public/sitemap.xml
@@ -0,0 +1,8 @@
+
+
+
+ https://frontendfixer.dev/
+ weekly
+ 1.0
+
+
diff --git a/public/twitter-image.png b/public/twitter-image.png
new file mode 100644
index 0000000..1922960
Binary files /dev/null and b/public/twitter-image.png differ
diff --git a/src/App.tsx b/src/App.tsx
index 04789dd..7e70868 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,18 +1,20 @@
import { Route, Routes } from 'react-router-dom';
-import Weeding from '#routes/Weeding';
+import { SEO } from '#/components/common/SEO';
+import Navigation from '#routes/Navigation.tsx';
import Home from './routes/Home';
-import Navigation from './routes/navigation';
const App = () => {
return (
-
- }>
- } />
-
- } />
-
+ <>
+
+
+ }>
+ } />
+
+
+ >
);
};
diff --git a/src/assets/images/portfolio/hero-dashboard.webp b/src/assets/images/portfolio/hero-dashboard.webp
new file mode 100644
index 0000000..0da2b4f
Binary files /dev/null and b/src/assets/images/portfolio/hero-dashboard.webp differ
diff --git a/src/assets/images/portfolio/profile-placeholder.webp b/src/assets/images/portfolio/profile-placeholder.webp
new file mode 100644
index 0000000..f13c16a
Binary files /dev/null and b/src/assets/images/portfolio/profile-placeholder.webp differ
diff --git a/src/assets/images/portfolio/vaultdrive-dashboard.webp b/src/assets/images/portfolio/vaultdrive-dashboard.webp
new file mode 100644
index 0000000..960c99d
Binary files /dev/null and b/src/assets/images/portfolio/vaultdrive-dashboard.webp differ
diff --git a/src/assets/images/portfolio/workspace-placeholder.png b/src/assets/images/portfolio/workspace-placeholder.png
new file mode 100644
index 0000000..835478c
Binary files /dev/null and b/src/assets/images/portfolio/workspace-placeholder.png differ
diff --git a/src/components/AltHeroSection.tsx b/src/components/AltHeroSection.tsx
deleted file mode 100644
index d1229bf..0000000
--- a/src/components/AltHeroSection.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import heroImage from '#assets/images/hero-alt.webp';
-// import HeroIllustration from '#assets/images/hero-illustration.webp';
-
-const AltHeroSection = () => {
- return (
-
-
-
- FullStack Web Developer
-
-
- Transforming Ideas into Immersive User Experiences with the Power of{' '}
- NodeJs and PHP
-
-
-
-
-
-
- );
-};
-
-export default AltHeroSection;
diff --git a/src/components/BackToTop.tsx b/src/components/BackToTop.tsx
deleted file mode 100644
index 120967f..0000000
--- a/src/components/BackToTop.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import { faArrowCircleUp } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { useEffect, useState } from 'react';
-
-const BackToTop = () => {
- const [visible, setVisible] = useState(false);
- const [top, setTop] = useState(0);
-
- const handleClick = () => {
- window.scrollTo({ top: 0, behavior: 'smooth' });
- };
-
- useEffect(() => {
- const intersectionObserver = new IntersectionObserver(entries => {
- setTop(entries[0].boundingClientRect.top);
- if (top <= 0) {
- return setVisible(true);
- } else setVisible(false);
- });
- window.addEventListener('scroll', () => {
- intersectionObserver.observe(document.querySelectorAll('section')[1]);
- });
- }, [top]);
-
- return (
-
-
-
-
-
- );
-};
-
-export default BackToTop;
diff --git a/src/components/Button.tsx b/src/components/Button.tsx
deleted file mode 100644
index 0b678a7..0000000
--- a/src/components/Button.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import { ReactNode } from 'react';
-
-import { cn } from '#/lib/cn';
-
-type ButtonType = {
- type?: 'button' | 'submit' | 'reset' | undefined;
- fullWidth?: boolean;
- children?: ReactNode;
- onClick?: () => void;
- buttonType?: 'secondary' | 'inverted' | undefined;
- disabled?: boolean;
- className?: string;
-};
-
-const Button = ({
- type,
- fullWidth,
- children,
- onClick,
- disabled,
- buttonType,
- className,
-}: ButtonType) => {
- return (
-
- {children}
-
- );
-};
-
-export default Button;
diff --git a/src/components/CVDownloadButton.tsx b/src/components/CVDownloadButton.tsx
deleted file mode 100644
index e557127..0000000
--- a/src/components/CVDownloadButton.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import Button from './Button';
-
-const downloadFile = () => {
- const element = document.createElement('a');
- element.href = '/Lakshmikanta.pdf';
- element.download = 'Lakshmikanta.pdf';
- document.body.appendChild(element);
- element.click();
-};
-
-const CVDownloadButton = ({
- buttonType,
-}: {
- buttonType?: 'secondary' | 'inverted' | undefined;
-}) => {
- return (
-
- Download CV
-
- );
-};
-
-export default CVDownloadButton;
diff --git a/src/components/Contact.tsx b/src/components/Contact.tsx
deleted file mode 100644
index 8447a14..0000000
--- a/src/components/Contact.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import { useSelector } from 'react-redux';
-
-import connectImg from '#assets/images/connect1.svg';
-import { RootState } from '#store/store';
-
-import ContactForm from './ContactForm';
-import MessageSent from './MessageSent';
-
-const Contact = () => {
- const { form } = useSelector((state: RootState) => state);
-
- return (
-
-
-
-
-
- {form.status !== 'completed' ? : }
-
-
- );
-};
-
-export default Contact;
diff --git a/src/components/ContactCapsule.tsx b/src/components/ContactCapsule.tsx
deleted file mode 100644
index 5cfb8a8..0000000
--- a/src/components/ContactCapsule.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-const ContactCapsule = () => {
- return (
-
-
- Get in touch with me
-
-
- );
-};
-
-export default ContactCapsule;
diff --git a/src/components/ContactForm.tsx b/src/components/ContactForm.tsx
deleted file mode 100644
index 802efa0..0000000
--- a/src/components/ContactForm.tsx
+++ /dev/null
@@ -1,156 +0,0 @@
-import emailjs from '@emailjs/browser';
-import { faPaperPlane } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { ChangeEvent, FormEvent, useRef, useState } from 'react';
-import { useDispatch, useSelector } from 'react-redux';
-import validator from 'validator';
-
-import { cn } from '#/lib/cn';
-import { setFormData, setFormStatus } from '#store/reducer/FormSlice';
-import { AppDispatch, RootState } from '#store/store';
-
-import Button from './Button';
-import Spinner from './Spinner';
-
-const ContactForm = () => {
- const initialState = { name: '', email: '', message: '' };
- const [inputs, setInputs] = useState(initialState);
- const formEl = useRef(null);
-
- const { form } = useSelector((state: RootState) => state);
- const dispatch: AppDispatch = useDispatch();
-
- const errors: { name: string; errorMessage: string }[] = [];
- const validationSchema = [
- {
- name: 'name',
- valid: validator.isLength(inputs.name, { min: 1 }),
- error: 'Name must be between 4-20 characters',
- },
- {
- name: 'email',
- valid: validator.isEmail(inputs.email),
- error: 'Enter valid email',
- },
- {
- name: 'message',
- valid: validator.isLength(inputs.message, { min: 20 }),
- error: 'Message must be at least 20 characters',
- },
- ];
- validationSchema.forEach(check => {
- if (!check.valid) {
- return errors.push({ name: check.name, errorMessage: check.error });
- }
- errors.filter(err => err.name === check.name);
- });
-
- const handleChange = (
- e: ChangeEvent,
- ) => {
- setInputs({ ...inputs, [e.target.name]: e.target.value });
- };
-
- const handelSubmit = async (e: FormEvent) => {
- e.preventDefault();
- if (errors.length > 0) return;
- dispatch(setFormData(inputs));
- dispatch(setFormStatus('loading'));
- if (formEl.current == null) throw new Error();
-
- const res = await emailjs.sendForm(
- 'service_qdjdol9',
- 'template_lobv7nq',
- formEl.current,
- 'G0MWsjYi9pbxnAwfJ',
- );
- if (res.status === 200) {
- return dispatch(setFormStatus('completed'));
- }
- return dispatch(setFormStatus('rejected'));
- };
-
- return (
-
- );
-};
-
-export default ContactForm;
diff --git a/src/components/Container.tsx b/src/components/Container.tsx
deleted file mode 100644
index cd0dada..0000000
--- a/src/components/Container.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import { ReactNode } from 'react';
-
-import { cn } from '#/lib/cn';
-
-const Container = ({
- children,
- fullWidth,
-}: {
- children: ReactNode;
- fullWidth?: boolean;
-}) => {
- return (
-
- {children}
-
- );
-};
-
-export default Container;
diff --git a/src/components/CountDown.tsx b/src/components/CountDown.tsx
deleted file mode 100644
index 004adca..0000000
--- a/src/components/CountDown.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import { Duration } from 'date-fns';
-
-// Helper function to format numbers with leading zeros (e.g., 5 -> 05)
-const formatTime = (time: number | undefined) => {
- return time && time < 10 ? `0${time}` : (time ?? 0);
-};
-
-// Main Countdown component
-const Countdown = ({ duration }: { duration: Duration }) => {
- return (
-
-
-
-
- {formatTime(duration.years ?? 0)}
-
-
Years
-
-
-
-
- {formatTime(duration.months ?? 0)}
-
-
Months
-
-
-
-
- {formatTime(duration.days)}
-
-
Days
-
-
-
- );
-};
-export default Countdown;
diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx
deleted file mode 100644
index 4f36e59..0000000
--- a/src/components/Footer.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import Logo from './Logo';
-import SocialLinks from './SocialLinks';
-
-const Footer = () => {
- return (
-
-
-
-
-
- Transforming Ideas into Immersive User Experiences with the Power of
- Web Development
-
-
-
-
-
-
- );
-};
-
-export default Footer;
diff --git a/src/components/GlassLaptopPanel.tsx b/src/components/GlassLaptopPanel.tsx
new file mode 100644
index 0000000..5504a85
--- /dev/null
+++ b/src/components/GlassLaptopPanel.tsx
@@ -0,0 +1,42 @@
+import { cn } from '#lib/utils';
+
+interface Props {
+ image: string;
+ alt: string;
+}
+
+export function GlassLaptopPanel({ image, alt }: Props) {
+ return (
+
+ {/* Background Glow */}
+
+
+
+ {/* Window Bar */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/ImageModal.tsx b/src/components/ImageModal.tsx
deleted file mode 100644
index ba3f74b..0000000
--- a/src/components/ImageModal.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import { faGithub } from '@fortawesome/free-brands-svg-icons';
-import { faClose, faEye } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-
-import { ProjectType } from '#data/Projects';
-
-const ImageModal = ({
- onClick,
- project,
-}: {
- onClick: () => void;
- project: ProjectType;
-}) => {
- return (
- <>
-
-
-
-
-
- {project.title}
-
-
-
-
-
- >
- );
-};
-
-export default ImageModal;
diff --git a/src/components/Intro.tsx b/src/components/Intro.tsx
deleted file mode 100644
index 241d430..0000000
--- a/src/components/Intro.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-const Intro = () => {
- return (
-
-
- Hi, I’m Lakshmikanta. Nice to meet you.
-
-
- Passionate about creating beautiful and functional websites and
- applications, with a solid foundation in Next.js, TypeScript, HTML5,
- CSS3, PHP, and MySQL. Eager to leverage creativity and technical skills
- to contribute to dynamic web development projects. Committed to
- continuous learning and staying updated with the latest industry trends.
-
-
- );
-};
-
-export default Intro;
diff --git a/src/components/LanguageAndTool.tsx b/src/components/LanguageAndTool.tsx
deleted file mode 100644
index b9a1157..0000000
--- a/src/components/LanguageAndTool.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-import AppsIcon from '#assets/images/icons/apps.svg?react';
-import BlocksIcon from '#assets/images/icons/blocks.svg?react';
-import CodeIcon from '#assets/images/icons/code.svg?react';
-import { frameworks, languages, tools } from '#data/Skills';
-
-const LanguageAndTool = () => {
- return (
-
-
-
-
-
-
- Languages
-
-
- {languages.map(({ id, name, Icon }) => (
-
-
-
{name}
-
- ))}
-
-
-
-
-
- {/*
*/}
-
-
- Frameworks
-
-
- {frameworks.map(({ id, name, Icon }) => (
-
-
-
{name}
-
- ))}
-
-
-
-
-
- {/*
*/}
-
-
- Tools
-
-
- {tools.map(({ id, name, Icon }) => (
-
-
-
{name}
-
- ))}
-
-
-
- );
-};
-
-export default LanguageAndTool;
diff --git a/src/components/Logo.tsx b/src/components/Logo.tsx
deleted file mode 100644
index 078f7a6..0000000
--- a/src/components/Logo.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import { Link } from 'react-router-dom';
-
-import { cn } from '#/lib/cn';
-
-const Logo = ({ large, variant }: { large?: boolean; variant: string }) => {
- return (
-
-
-
-
-
-
-
-
- );
-};
-
-export default Logo;
diff --git a/src/components/MessageSent.tsx b/src/components/MessageSent.tsx
deleted file mode 100644
index eea1192..0000000
--- a/src/components/MessageSent.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import { useSelector } from 'react-redux';
-
-import sendIcon from '#assets/images/message_send.svg';
-import { RootState } from '#store/store';
-
-const MessageSent = () => {
- const {
- form: {
- data: { name },
- },
- } = useSelector((state: RootState) => state);
-
- return (
-
-
-
-
- Thank you!
-
- {name}
-
-
-
We will get to you soon.
-
-
- );
-};
-
-export default MessageSent;
diff --git a/src/components/NavigationMenu.tsx b/src/components/NavigationMenu.tsx
deleted file mode 100644
index f53fa83..0000000
--- a/src/components/NavigationMenu.tsx
+++ /dev/null
@@ -1,101 +0,0 @@
-import { MouseEvent } from 'react';
-
-import { cn } from '#/lib/cn';
-
-import CVDownloadButton from './CVDownloadButton';
-import ThemeSwitcher from './ThemeSwitcher';
-
-type MenuItem = {
- id: number;
- itemName: string;
- path: string;
-};
-const menuItems: MenuItem[] = [
- {
- id: 1,
- itemName: 'About',
- path: '#about',
- },
- {
- id: 2,
- itemName: 'Projects',
- path: '#projects',
- },
- {
- id: 3,
- itemName: 'Contact',
- path: '#contact',
- },
-];
-
-const NavigationMenu = ({ openState }: { openState: boolean }) => {
- const handelNavigation = (e: MouseEvent) => {
- e.preventDefault();
- const path = (e.target as HTMLAnchorElement).getAttribute('href');
- if (!path) return;
- document.querySelector(path)?.scrollIntoView({
- behavior: 'smooth',
- block: 'start',
- inline: 'start',
- });
- };
-
- return (
- <>
- {/* Desktop Navbar */}
-
-
-
-
-
- {/* Mobile Navbar */}
-
-
-
- >
- );
-};
-
-export default NavigationMenu;
diff --git a/src/components/ProjectCard.tsx b/src/components/ProjectCard.tsx
deleted file mode 100644
index 4eee0d4..0000000
--- a/src/components/ProjectCard.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-import { faGithub } from '@fortawesome/free-brands-svg-icons';
-import { faEye } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { useState } from 'react';
-
-import { ProjectType } from '#data/Projects';
-
-import ImageModal from './ImageModal';
-
-const ProjectCard = ({ project }: { project: ProjectType }) => {
- const [openModal, setOpenModal] = useState(false);
-
- const handelImageClick = () => {
- setOpenModal(!openModal);
- };
- const handelClose = () => {
- setOpenModal(!openModal);
- };
-
- return (
-
- <>
-
-
- {openModal && }
-
- >
-
-
-
- {project.title}
-
-
-
- Coding done with
-
-
- {project.development.language
- ?.filter(el => el !== 'HTML' && el !== 'CSS')
- .map((el, i) => (
-
- #{el}
-
- ))}
-
-
-
-
-
- );
-};
-
-export default ProjectCard;
diff --git a/src/components/RecentWork.tsx b/src/components/RecentWork.tsx
deleted file mode 100644
index 3441fe9..0000000
--- a/src/components/RecentWork.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import Projects from '#data/Projects';
-
-import ProjectCard from './ProjectCard';
-
-const featuredProject = Projects.filter(project => project.featured);
-
-const RecentWork = () => {
- return (
-
- {featuredProject.map(project => {
- return
;
- })}
-
- );
-};
-
-export default RecentWork;
diff --git a/src/components/SocialLinks.tsx b/src/components/SocialLinks.tsx
deleted file mode 100644
index a66239c..0000000
--- a/src/components/SocialLinks.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-
-import { cn } from '#/lib/cn';
-import { SocialLink, socialLinks } from '#data/Social';
-
-const SocialLinks = ({ inverted }: { inverted?: boolean }) => {
- return (
-
- {socialLinks.map((link: SocialLink) => (
-
-
-
- ))}
-
- );
-};
-
-export default SocialLinks;
diff --git a/src/components/Spinner.tsx b/src/components/Spinner.tsx
deleted file mode 100644
index b2ac18a..0000000
--- a/src/components/Spinner.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import { cn } from '#/lib/cn';
-
-const Spinner = ({ size }: { size: number }) => {
- return (
-
- Loading...
-
- );
-};
-
-export default Spinner;
diff --git a/src/components/ThemeSwitcher.tsx b/src/components/ThemeSwitcher.tsx
deleted file mode 100644
index bd9e047..0000000
--- a/src/components/ThemeSwitcher.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import { useEffect } from 'react';
-import { useDispatch, useSelector } from 'react-redux';
-
-import { toggleTheme } from '#store/reducer/ThemeReducer';
-import { RootState } from '#store/store';
-
-import ToggleButton from './ToggleButton';
-
-const ThemeSwitcher = ({ className }: { className?: string }) => {
- const theme = useSelector((state: RootState) => state.theme);
- const dispatch = useDispatch();
-
- const handleChange = () => {
- const setTheme = theme === 'dark' ? 'light' : 'dark';
- dispatch(toggleTheme(setTheme));
- };
-
- useEffect(() => {
- document.documentElement.removeAttribute('class');
- document.documentElement.classList.add(theme);
- localStorage.setItem('theme', theme);
- }, [theme]);
- return (
-
-
-
- );
-};
-
-export default ThemeSwitcher;
diff --git a/src/components/ToggleButton.tsx b/src/components/ToggleButton.tsx
deleted file mode 100644
index 173fdc7..0000000
--- a/src/components/ToggleButton.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import { faMoon, faSun } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-
-import { cn } from '#/lib/cn';
-
-const ToggleButton = ({
- isDarkMode,
- onClick,
-}: {
- isDarkMode: boolean;
- onClick: () => void;
-}) => {
- return (
-
-
-
-
-
- );
-};
-
-export default ToggleButton;
diff --git a/src/components/common/SEO.tsx b/src/components/common/SEO.tsx
new file mode 100644
index 0000000..9192bfc
--- /dev/null
+++ b/src/components/common/SEO.tsx
@@ -0,0 +1,136 @@
+import { Helmet } from 'react-helmet-async';
+
+import { siteConfig } from '#/config/site';
+
+export interface SEOProps {
+ title?: string;
+ description?: string;
+ image?: string;
+ url?: string;
+ type?: string;
+ keywords?: string[];
+}
+
+function resolveUrl(path: string): string {
+ if (path.startsWith('http://') || path.startsWith('https://')) {
+ return path;
+ }
+
+ const base = siteConfig.url.replace(/\/$/, '');
+ const normalizedPath = path.startsWith('/') ? path : `/${path}`;
+
+ return `${base}${normalizedPath}`;
+}
+
+function buildTitle(pageTitle?: string): string {
+ if (!pageTitle) {
+ return siteConfig.title;
+ }
+
+ if (pageTitle === siteConfig.siteName || pageTitle === siteConfig.title) {
+ return siteConfig.title;
+ }
+
+ return `${pageTitle} | ${siteConfig.siteName}`;
+}
+
+function buildStructuredData() {
+ const logoUrl = resolveUrl('/android-chrome-512x512.png');
+ const sameAs = [siteConfig.github, siteConfig.linkedin];
+
+ const person = {
+ '@context': 'https://schema.org',
+ '@type': 'Person',
+ name: siteConfig.author,
+ url: siteConfig.url,
+ email: siteConfig.email,
+ jobTitle: 'Full Stack Engineer',
+ sameAs,
+ };
+
+ const website = {
+ '@context': 'https://schema.org',
+ '@type': 'WebSite',
+ name: siteConfig.siteName,
+ url: siteConfig.url,
+ description: siteConfig.description,
+ inLanguage: siteConfig.language,
+ publisher: {
+ '@type': 'Organization',
+ name: siteConfig.siteName,
+ url: siteConfig.url,
+ },
+ };
+
+ const organization = {
+ '@context': 'https://schema.org',
+ '@type': 'Organization',
+ name: siteConfig.siteName,
+ url: siteConfig.url,
+ logo: logoUrl,
+ email: siteConfig.email,
+ sameAs,
+ };
+
+ return { person, website, organization };
+}
+
+export function SEO({
+ title,
+ description,
+ image,
+ url,
+ type,
+ keywords,
+}: SEOProps = {}) {
+ const resolvedTitle = buildTitle(title);
+ const resolvedDescription = description ?? siteConfig.description;
+ const resolvedUrl = resolveUrl(url ?? '/');
+ const resolvedImage = resolveUrl(image ?? '/og-image.png');
+ const resolvedTwitterImage = resolveUrl(image ?? '/twitter-image.png');
+ const resolvedType = type ?? siteConfig.openGraph.type;
+ const resolvedKeywords = (keywords ?? siteConfig.keywords).join(', ');
+ const { person, website, organization } = buildStructuredData();
+
+ return (
+
+
+
+ {resolvedTitle}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/sections/About.tsx b/src/components/sections/About.tsx
new file mode 100644
index 0000000..1b1c9d9
--- /dev/null
+++ b/src/components/sections/About.tsx
@@ -0,0 +1,127 @@
+import { ArrowUpRight, BriefcaseBusiness, Cloud, Code2 } from 'lucide-react';
+
+import profilePlaceholder from '#assets/images/portfolio/profile-placeholder.webp';
+
+import { Reveal } from '../ui/Reveal';
+import { Section } from '../ui/Section';
+
+const strengths = [
+ {
+ icon: Code2,
+ title: 'Full Stack Development',
+ description: 'Modern React, TypeScript, NestJS and scalable APIs.',
+ },
+ {
+ icon: Cloud,
+ title: 'Cloud Architecture',
+ description:
+ 'AWS, serverless workloads, storage and backend infrastructure.',
+ },
+ {
+ icon: BriefcaseBusiness,
+ title: 'Product Engineering',
+ description: 'Building SaaS products from MVP to production.',
+ },
+];
+
+export function About() {
+ return (
+
+
+ {/* Image */}
+
+
+
+
+
+
+
+
+ Available
+
+
+
+ For Freelance Projects
+
+
+
+
+
+ {/* Content */}
+
+
+
+ About Me
+
+
+
+ Building modern SaaS products with
+
+ {' '}
+ scalable architecture
+
+ .
+
+
+
+
+
+ I'm Lakshmikanta Patra, a Full Stack Engineer focused on building
+ secure, scalable SaaS applications with React, NestJS, TypeScript,
+ and AWS.
+
+
+
+ I enjoy solving backend architecture challenges, designing
+ cloud-native systems, and creating clean user experiences that are
+ fast, maintainable, and built for long-term growth.
+
+
+
+ {/* Strengths */}
+
+
+ {strengths.map(item => {
+ const Icon = item.icon;
+
+ return (
+
+
+
+
{item.title}
+
+
+ {item.description}
+
+
+ );
+ })}
+
+
+
+ {/* CTA */}
+
+
+ Let's build something great together
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/sections/Contact.tsx b/src/components/sections/Contact.tsx
new file mode 100644
index 0000000..6c55f0d
--- /dev/null
+++ b/src/components/sections/Contact.tsx
@@ -0,0 +1,187 @@
+import emailjs from '@emailjs/browser';
+import { faGithub, faLinkedin } from '@fortawesome/free-brands-svg-icons';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { ArrowUpRight, Loader2, Mail, MapPin, Send } from 'lucide-react';
+import { ChangeEvent, FormEvent, useMemo, useRef, useState } from 'react';
+import validator from 'validator';
+
+import workspaceImage from '#assets/images/portfolio/workspace-placeholder.png';
+
+import { Button } from '../ui/Button';
+import { Reveal } from '../ui/Reveal';
+import { Section } from '../ui/Section';
+
+export function Contact() {
+ const initial = { name: '', email: '', message: '' };
+ const [inputs, setInputs] = useState(initial);
+ const [status, setStatus] = useState<
+ 'idle' | 'loading' | 'completed' | 'rejected'
+ >('idle');
+ const formRef = useRef(null);
+
+ const errors = useMemo(
+ () => ({
+ name: inputs.name.trim().length < 2,
+ email: !validator.isEmail(inputs.email),
+ message: inputs.message.trim().length < 20,
+ }),
+ [inputs],
+ );
+
+ const invalid = errors.name || errors.email || errors.message;
+
+ const onChange = (e: ChangeEvent) =>
+ setInputs(v => ({ ...v, [e.target.name]: e.target.value }));
+
+ const onSubmit = async (e: FormEvent) => {
+ e.preventDefault();
+ if (invalid || !formRef.current) return;
+ setStatus('loading');
+ try {
+ const res = await emailjs.sendForm(
+ 'service_qdjdol9',
+ 'template_lobv7nq',
+ formRef.current,
+ 'G0MWsjYi9pbxnAwfJ',
+ );
+ if (res.status === 200) {
+ setInputs(initial);
+ setStatus('completed');
+ } else setStatus('rejected');
+ } catch {
+ setStatus('rejected');
+ }
+ };
+
+ return (
+
+ );
+}
diff --git a/src/components/sections/ContactButton.tsx b/src/components/sections/ContactButton.tsx
new file mode 100644
index 0000000..0b93b27
--- /dev/null
+++ b/src/components/sections/ContactButton.tsx
@@ -0,0 +1,21 @@
+import { ArrowRight } from 'lucide-react';
+
+import { Button } from '#components/ui/Button.tsx';
+
+interface ContactButtonProps {
+ text?: string;
+ className?: string;
+}
+
+export function ContactButton({ text, className }: ContactButtonProps) {
+ return (
+
+
+
+ {text ?? 'Start Your Project'}
+
+
+
+
+ );
+}
diff --git a/src/components/sections/FAQ.tsx b/src/components/sections/FAQ.tsx
new file mode 100644
index 0000000..07242ed
--- /dev/null
+++ b/src/components/sections/FAQ.tsx
@@ -0,0 +1,87 @@
+import { ChevronDown } from 'lucide-react';
+import { useState } from 'react';
+
+import { cn } from '#lib/utils';
+
+import { Reveal } from '../ui/Reveal';
+import { Section } from '../ui/Section';
+
+const faqs = [
+ {
+ question: 'How do we get started?',
+ answer:
+ "We'll begin with a discovery call to discuss your project goals, technical requirements, timeline, and budget. After that, I'll provide a clear proposal with milestones and estimated delivery.",
+ },
+ {
+ question: 'What kinds of projects do you work on?',
+ answer:
+ 'I build modern SaaS applications, custom web platforms, REST APIs, cloud-native backend systems, and scalable frontend applications using React, Next.js, NestJS, TypeScript, and AWS.',
+ },
+ {
+ question: 'Can you improve or maintain an existing application?',
+ answer:
+ 'Absolutely. I can optimize performance, refactor legacy code, implement new features, migrate applications to modern architectures, and provide ongoing maintenance and technical support.',
+ },
+ {
+ question: 'Do you provide post-launch support?',
+ answer:
+ 'Yes. I offer post-launch maintenance, bug fixes, feature enhancements, infrastructure improvements, and long-term technical support to keep your application reliable and scalable.',
+ },
+];
+
+export function FAQ() {
+ const [openIndex, setOpenIndex] = useState(null);
+
+ return (
+
+
+
+
+ Common Questions
+
+
+ Details about my process, availability, and how we can work
+ together.
+
+
+
+
+
+ {faqs.map((faq, i) => (
+
+
+
setOpenIndex(openIndex === i ? null : i)}
+ >
+
+ {faq.question}
+
+
+
+
+
+
+ ))}
+
+
+ );
+}
diff --git a/src/components/sections/FeaturedProject.tsx b/src/components/sections/FeaturedProject.tsx
new file mode 100644
index 0000000..25f1a69
--- /dev/null
+++ b/src/components/sections/FeaturedProject.tsx
@@ -0,0 +1,137 @@
+import { faExternalLink } from '@fortawesome/free-solid-svg-icons';
+import { CheckCircle2, Lock, Rocket, Server } from 'lucide-react';
+
+import vaultDashboard from '#assets/images/portfolio/vaultdrive-dashboard.webp';
+import { GlassLaptopPanel } from '#components/GlassLaptopPanel';
+import { LinkButton } from '#components/ui/LinkButton';
+
+import { Reveal } from '../ui/Reveal';
+import { Section } from '../ui/Section';
+
+const highlights = [
+ {
+ icon: Lock,
+ title: 'Secure',
+ value: 'RBAC & ABAC',
+ },
+ {
+ icon: Rocket,
+ title: 'Scalable',
+ value: 'Lambda + SQS',
+ },
+ {
+ icon: Server,
+ title: 'Cloud Native',
+ value: 'AWS + Cloudflare R2',
+ },
+];
+
+const features = [
+ 'Multi Bucket Storage',
+ 'Frontend Presigned Uploads',
+ 'Background Workers',
+ 'Thumbnail Processing',
+];
+
+const technologies = [
+ 'TanStack Start',
+ 'NestJS',
+ 'AWS',
+ 'Lambda',
+ 'Prisma',
+ 'Docker',
+ 'MySQL',
+ 'Cloudflare R2',
+];
+
+export function FeaturedProject() {
+ return (
+
+
+
+
+
+ Featured Project
+
+
+
VaultDrive
+
+
+ Enterprise cloud storage platform built for secure file management,
+ scalable uploads, and modern cloud infrastructure.
+
+
+
+
+
+ {/* Screenshot */}
+
+
+
+
+ {/* Content */}
+
+ {/* Highlight Cards */}
+
+
+ {highlights.map(item => {
+ const Icon = item.icon;
+
+ return (
+
+
+
+
{item.title}
+
+
{item.value}
+
+ );
+ })}
+
+
+
+ {/* Feature List */}
+
+
+ {features.map(feature => (
+
+
+
+ {feature}
+
+ ))}
+
+
+
+ {/* Technology */}
+
+
+ {technologies.map(tech => (
+
+ {tech}
+
+ ))}
+
+
+
+ {/* CTA */}
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/sections/Footer.tsx b/src/components/sections/Footer.tsx
new file mode 100644
index 0000000..d02ab9d
--- /dev/null
+++ b/src/components/sections/Footer.tsx
@@ -0,0 +1,115 @@
+import { faGithub, faLinkedin } from '@fortawesome/free-brands-svg-icons';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { ArrowUpRight, Mail } from 'lucide-react';
+
+import { Container } from '../ui/Container';
+
+export function Footer() {
+ const year = new Date().getFullYear();
+
+ return (
+
+
+
+ {/* Brand */}
+
+
+ {/* Navigation */}
+
+
+ {/* Connect */}
+
+
+
+
+
+ © {year} Lakshmikanta Patra. Built with React, TypeScript & Tailwind
+ CSS.
+
+
+
+ Back to top
+
+
+
+
+
+ );
+}
diff --git a/src/components/sections/HeroSection.tsx b/src/components/sections/HeroSection.tsx
new file mode 100644
index 0000000..cc0ebab
--- /dev/null
+++ b/src/components/sections/HeroSection.tsx
@@ -0,0 +1,104 @@
+import { Briefcase } from 'lucide-react';
+import { ReactNode } from 'react';
+
+import heroDashboard from '#assets/images/portfolio/hero-dashboard.webp';
+import { GlassLaptopPanel } from '#components/GlassLaptopPanel';
+import { ContactButton } from '#components/sections/ContactButton';
+
+import { Container } from '../ui/Container';
+import { Reveal } from '../ui/Reveal';
+
+function Accent({ children }: { children: ReactNode }) {
+ return (
+
+ {children}
+
+ );
+}
+
+function TrustItem({ children }: { children: ReactNode }) {
+ return (
+
+
+ {children}
+
+ );
+}
+
+export function HeroSection() {
+ return (
+
+ {/* Background Glow */}
+
+
+
+
+
+ {/* Availability Badge */}
+
+
+
+
+ Available for freelance projects
+
+
+
+
+ {/* Headline */}
+
+
+ I build production-ready SaaS platforms
+
+ from MVP to enterprise-grade infrastructure
+
+
+
+ {/* Description */}
+
+
+ I help startups and growing businesses design, build, and scale
+ secure cloud-native SaaS products using React, NestJS, AWS, and
+ modern backend architecture.
+
+
+
+ {/* CTA */}
+
+
+
+
+ {/* Trust Row */}
+
+
+ Available for freelance
+ Remote worldwide
+ Replies within 24 hours
+
+
+
+
+ {/* Hero Image */}
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/sections/Metrics.tsx b/src/components/sections/Metrics.tsx
new file mode 100644
index 0000000..cea6470
--- /dev/null
+++ b/src/components/sections/Metrics.tsx
@@ -0,0 +1,32 @@
+import { Container } from '../ui/Container';
+import { Reveal } from '../ui/Reveal';
+const metrics = [
+ { value: '30+', label: 'Projects shipped' },
+ { value: '4+', label: 'Years in production' },
+ { value: '100%', label: 'On-time delivery' },
+ { value: '0', label: 'Data-loss incidents' },
+];
+export function Metrics() {
+ return (
+
+
+
+ {metrics.map((metric, i) => (
+
+
+ {metric.value}
+
+
+ {metric.label}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/components/sections/Process.tsx b/src/components/sections/Process.tsx
new file mode 100644
index 0000000..d806c60
--- /dev/null
+++ b/src/components/sections/Process.tsx
@@ -0,0 +1,83 @@
+import { LifeBuoy, PenTool, Rocket, Search, Terminal } from 'lucide-react';
+
+import { Reveal } from '../ui/Reveal';
+import { Section } from '../ui/Section';
+const processSteps = [
+ {
+ icon: Search,
+ title: 'Discover',
+ description:
+ 'Understanding your business goals, users, and technical requirements to define a clear scope.',
+ },
+ {
+ icon: PenTool,
+ title: 'Plan',
+ description:
+ 'Architecting the database schema, API design, and selecting the optimal technology stack.',
+ },
+ {
+ icon: Terminal,
+ title: 'Develop',
+ description:
+ 'Writing clean, typed, and tested code using modern frameworks and best practices.',
+ },
+ {
+ icon: Rocket,
+ title: 'Deploy',
+ description:
+ 'Setting up CI/CD pipelines and deploying to cloud infrastructure with zero downtime.',
+ },
+ {
+ icon: LifeBuoy,
+ title: 'Support',
+ description:
+ 'Monitoring performance, fixing edge-case bugs, and scaling architecture as needed.',
+ },
+];
+export function Process() {
+ return (
+
+
+
+
+ Development Process
+
+
+ A structured, transparent approach to delivering enterprise-grade
+ software on time.
+
+
+
+
+
+
+ {processSteps.map((step, i) => {
+ const isEven = i % 2 === 0;
+ return (
+
+
+
+
+ {step.title}
+
+
{step.description}
+
+
+
+
+
+ );
+ })}
+
+
+
+ );
+}
diff --git a/src/components/sections/Services.tsx b/src/components/sections/Services.tsx
new file mode 100644
index 0000000..ac1e85a
--- /dev/null
+++ b/src/components/sections/Services.tsx
@@ -0,0 +1,60 @@
+import { Code2, Cpu, Database } from 'lucide-react';
+
+import { Reveal } from '../ui/Reveal';
+import { Section } from '../ui/Section';
+
+const services = [
+ {
+ icon: Code2,
+ title: 'SaaS & MVP Development',
+ description:
+ 'End-to-end product builds — from architecture to launch, with REST/GraphQL APIs built on NestJS.',
+ },
+ {
+ icon: Database,
+ title: 'Backend & Cloud Architecture',
+ description:
+ 'Resilient database schemas, microservices, and AWS/Docker/Cloudflare deployments tailored for scale.',
+ },
+ {
+ icon: Cpu,
+ title: 'Performance & Technical Consulting',
+ description:
+ 'Auditing and accelerating slow Next.js/Node.js apps, plus strategic guidance for early-stage teams.',
+ },
+];
+export function Services() {
+ return (
+
+
+
+
+
+
+ Expertise & Services
+
+
+ I specialize in the technical foundation required to launch and
+ scale successful software products.
+
+
+
+
+
+ {services.map((service, i) => (
+
+
+
+
+
+
{service.title}
+
+ {service.description}
+
+
+
+ ))}
+
+
+ );
+}
diff --git a/src/components/sections/TechStack.tsx b/src/components/sections/TechStack.tsx
new file mode 100644
index 0000000..66f7ccd
--- /dev/null
+++ b/src/components/sections/TechStack.tsx
@@ -0,0 +1,74 @@
+import { Reveal } from '../ui/Reveal';
+import { Section } from '../ui/Section';
+
+const techGroups = [
+ {
+ category: 'Frontend',
+ items: ['React', 'Next.js', 'TypeScript', 'Tailwind CSS', 'React Query'],
+ },
+ {
+ category: 'Backend',
+ items: ['NestJS', 'Node.js', 'REST APIs', 'GraphQL', 'Prisma ORM'],
+ },
+ {
+ category: 'Cloud & DevOps',
+ items: [
+ 'AWS',
+ 'Lambda',
+ 'S3',
+ 'Cloudflare',
+ 'Docker',
+ 'GitHub Actions',
+ 'CI/CD',
+ ],
+ },
+ {
+ category: 'Databases',
+ items: ['MySQL', 'PostgreSQL', 'Redis'],
+ },
+];
+
+export function TechStack() {
+ return (
+
+
+
+
+ Technical Arsenal
+
+
+ I build with modern, battle-tested technologies optimized for
+ developer experience and application performance.
+
+
+
+
+
+ {techGroups.map((group, i) => (
+
+
+
+
+
+ {group.category}
+
+
+
+
+
+ {group.items.map(tech => (
+
+ {tech}
+
+ ))}
+
+
+
+ ))}
+
+
+ );
+}
diff --git a/src/components/sections/Testimonials.tsx b/src/components/sections/Testimonials.tsx
new file mode 100644
index 0000000..5b664f8
--- /dev/null
+++ b/src/components/sections/Testimonials.tsx
@@ -0,0 +1,64 @@
+import { Quote } from 'lucide-react';
+
+import { Reveal } from '../ui/Reveal';
+import { Section } from '../ui/Section';
+
+const testimonials = [
+ {
+ quote:
+ "An exceptional engineer who doesn't just write code, but solves complex business problems. Delivered our entire cloud infrastructure ahead of schedule.",
+ author: 'Sarah J.',
+ role: 'CTO, TechStartup',
+ },
+ {
+ quote:
+ 'Transformed our legacy monolith into a performant, scalable Next.js and Node.js architecture. The performance gains were immediate.',
+ author: 'Michael T.',
+ role: 'Engineering Manager',
+ },
+ {
+ quote:
+ 'Clean code, excellent communication, and a deep understanding of modern SaaS architecture. Highly recommended for any serious technical project.',
+ author: 'Elena R.',
+ role: 'Founder',
+ },
+];
+
+export function Testimonials() {
+ return (
+
+
+
+
+ Client Feedback
+
+
+ What engineering leaders and founders say about my work.
+
+
+
+
+
+ {testimonials.map((t, i) => (
+
+
+
+
+ "{t.quote}"
+
+
+
+ {t.author.charAt(0)}
+
+
+
{t.author}
+
{t.role}
+
+
+
+
+ ))}
+
+
+ );
+}
diff --git a/src/components/sections/TrustStrip.tsx b/src/components/sections/TrustStrip.tsx
new file mode 100644
index 0000000..01081de
--- /dev/null
+++ b/src/components/sections/TrustStrip.tsx
@@ -0,0 +1,57 @@
+import { CheckCircle2 } from 'lucide-react';
+
+import { Container } from '../ui/Container';
+
+const expertise = [
+ 'Full Stack Engineer',
+ 'Next.js',
+ 'NestJS',
+ 'AWS',
+ 'Cloud Architecture',
+ 'TypeScript',
+];
+
+const trustSignals = [
+ 'Available for Freelance',
+ 'Replies within 24 Hours',
+ 'Remote Worldwide',
+];
+
+export function TrustStrip() {
+ return (
+
+
+
+ {/* Expertise */}
+
+ {expertise.map(item => (
+
+
+ {item}
+
+ ))}
+
+
+ {/* Divider */}
+
+
+ {/* Trust Signals */}
+
+ {trustSignals.map(item => (
+
+
+ {item}
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/src/components/ui/Button.tsx b/src/components/ui/Button.tsx
new file mode 100644
index 0000000..a1f7f86
--- /dev/null
+++ b/src/components/ui/Button.tsx
@@ -0,0 +1,50 @@
+import { Slot } from '@radix-ui/react-slot';
+import { forwardRef } from 'react';
+
+import { cn } from '#lib/utils';
+
+export interface ButtonProps extends React.ButtonHTMLAttributes {
+ variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'link' | 'cta';
+ size?: 'sm' | 'md' | 'lg' | 'icon';
+ asChild?: boolean;
+}
+
+const Button = forwardRef(
+ (
+ { className, variant = 'primary', size = 'md', asChild = false, ...props },
+ ref,
+ ) => {
+ const Comp = asChild ? Slot : 'button';
+
+ return (
+
+ );
+ },
+);
+Button.displayName = 'Button';
+
+export { Button };
diff --git a/src/components/ui/Container.tsx b/src/components/ui/Container.tsx
new file mode 100644
index 0000000..8621c5f
--- /dev/null
+++ b/src/components/ui/Container.tsx
@@ -0,0 +1,16 @@
+import React, { ReactNode } from 'react';
+
+import { cn } from '#lib/utils';
+
+interface ContainerProps extends React.HTMLAttributes {
+ children: ReactNode;
+ className?: string;
+}
+
+export function Container({ children, className }: ContainerProps) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/components/ui/LinkButton.tsx b/src/components/ui/LinkButton.tsx
new file mode 100644
index 0000000..4345aa0
--- /dev/null
+++ b/src/components/ui/LinkButton.tsx
@@ -0,0 +1,30 @@
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import React from 'react';
+
+import { Button } from '#components/ui/Button.tsx';
+
+interface LinkButtonProps extends React.HTMLAttributes {
+ href: string;
+ label: string;
+ icon: IconProp;
+ variant?: 'primary' | 'secondary';
+ className?: string;
+}
+
+export function LinkButton({
+ href,
+ label,
+ icon,
+ variant = 'secondary',
+ className,
+}: LinkButtonProps) {
+ return (
+
+
+ {label}
+
+
+
+ );
+}
diff --git a/src/components/ui/Reveal.tsx b/src/components/ui/Reveal.tsx
new file mode 100644
index 0000000..b1ac8f6
--- /dev/null
+++ b/src/components/ui/Reveal.tsx
@@ -0,0 +1,39 @@
+import { motion, useReducedMotion } from 'framer-motion';
+import { ReactNode } from 'react';
+
+import { cn } from '#lib/utils';
+
+interface RevealProps {
+ children: ReactNode;
+ width?: 'fit-content' | '100%';
+ delay?: number;
+ className?: string;
+}
+
+const VIEWPORT = { once: true, margin: '-50px' };
+
+export function Reveal({
+ children,
+ width = '100%',
+ delay = 0,
+ className,
+}: RevealProps) {
+ const shouldReduceMotion = useReducedMotion();
+
+ return (
+
+
+ {children}
+
+
+ );
+}
diff --git a/src/components/ui/Section.tsx b/src/components/ui/Section.tsx
new file mode 100644
index 0000000..556d6f4
--- /dev/null
+++ b/src/components/ui/Section.tsx
@@ -0,0 +1,25 @@
+import React, { ReactNode } from 'react';
+
+import { cn } from '#lib/utils';
+
+interface SectionProps extends React.HTMLAttributes {
+ id?: string;
+ children: ReactNode;
+ containerClass?: string;
+ className?: string;
+}
+
+import { Container } from './Container';
+
+export function Section({
+ id,
+ className,
+ children,
+ containerClass,
+}: SectionProps) {
+ return (
+
+ );
+}
diff --git a/src/config/site.ts b/src/config/site.ts
new file mode 100644
index 0000000..f62675f
--- /dev/null
+++ b/src/config/site.ts
@@ -0,0 +1,77 @@
+export interface OpenGraphConfig {
+ type: string;
+ image: string;
+ imageWidth: number;
+ imageHeight: number;
+ siteName: string;
+}
+
+export interface TwitterConfig {
+ card: 'summary' | 'summary_large_image' | 'app' | 'player';
+ site: string;
+ creator: string;
+ image: string;
+}
+
+export interface SiteConfig {
+ siteName: string;
+ title: string;
+ description: string;
+ url: string;
+ locale: string;
+ language: string;
+ author: string;
+ email: string;
+ github: string;
+ linkedin: string;
+ themeColor: string;
+ backgroundColor: string;
+ keywords: string[];
+ twitter: TwitterConfig;
+ openGraph: OpenGraphConfig;
+ robots: string;
+}
+
+const siteUrl = 'https://frontendfixer.dev';
+
+export const siteConfig: SiteConfig = {
+ siteName: 'FrontendFixer',
+ title: 'FrontendFixer | Full-Stack Developer for SaaS & MVPs',
+ description:
+ 'I help startups and growing businesses design, build, and scale secure cloud-native SaaS products using React, NestJS, AWS, and modern backend architecture.',
+ url: siteUrl,
+ locale: 'en_US',
+ language: 'en',
+ author: 'Lakshmikanta Patra',
+ email: 'frontendfixer@email.com',
+ github: 'https://github.com/frontendfixer',
+ linkedin: 'https://linkedin.com/in/frontendfixer',
+ themeColor: '#14b8a6',
+ backgroundColor: '#09090B',
+ keywords: [
+ 'full stack developer',
+ 'SaaS developer',
+ 'MVP development',
+ 'React developer',
+ 'NestJS',
+ 'TypeScript',
+ 'AWS',
+ 'freelance developer',
+ 'cloud-native applications',
+ 'FrontendFixer',
+ ],
+ twitter: {
+ card: 'summary_large_image',
+ site: '@frontendfixer',
+ creator: '@frontendfixer',
+ image: `${siteUrl}/twitter-image.png`,
+ },
+ openGraph: {
+ type: 'website',
+ image: `${siteUrl}/og-image.png`,
+ imageWidth: 1200,
+ imageHeight: 630,
+ siteName: 'FrontendFixer',
+ },
+ robots: 'index, follow',
+};
diff --git a/src/data/Projects.ts b/src/data/Projects.ts
deleted file mode 100644
index e2b71a2..0000000
--- a/src/data/Projects.ts
+++ /dev/null
@@ -1,117 +0,0 @@
-import demoImg from '/demo.webp';
-
-import crwnClothing from './screenshot/crwn-clothing.webp';
-import elctricSkateboards from './screenshot/electric-skateboards-USA.webp';
-import forkifyRecipe from './screenshot/forkify-recipe-js.webp';
-import openTable from './screenshot/open-table.webp';
-import adminDashboard from './screenshot/react-admin-dashboard.webp';
-
-export type ProjectType = {
- id: number;
- title: string;
- description?: string;
- image: string;
- repo: string;
- url: string;
- development: {
- language?: string[];
- tools?: string[];
- };
- featured: boolean;
-};
-
-const Projects: ProjectType[] = [
- {
- id: 1,
- title: 'Crwn Clothing Online Store',
- description: 'This is a project 1',
- image: crwnClothing,
- repo: 'https://github.com/frontendfixer/crwn-clothing-redux',
- url: 'https://crwn-clothing-redux.vercel.app',
- development: {
- language: [
- 'firebase',
- 'react',
- 'typescript',
- 'HTML',
- 'CSS',
- 'redux',
- 'styled_components',
- ],
- },
- featured: true,
- },
- {
- id: 2,
- title: 'Open Table | Book a Table at Any Restaurant',
- description: 'This is a project 2',
- image: openTable,
- repo: 'https://github.com/frontendfixer/OpenTable-NextJS-App',
- url: 'https://open-table-next-js-app.vercel.app',
- development: {
- language: [
- 'nextjs',
- 'react',
- 'typescript',
- 'redux',
- 'MUI',
- 'prisma',
- 'postgreSQL',
- 'HTML',
- 'CSS',
- ],
- },
- featured: true,
- },
- {
- id: 3,
- title: 'Admin Dashboard | Build with React',
- description: 'This is a project 2',
- image: adminDashboard,
- repo: 'https://github.com/frontendfixer/react-admin-ui',
- url: 'https://react-admin-dashboard-self.vercel.app/',
- development: {
- language: ['react', 'typescript', 'recharts', 'MUI', 'HTML', 'CSS'],
- },
- featured: true,
- },
- {
- id: 4,
- title: 'Forkify | Search Recipe with Ingredients',
- description: 'This is a project 4',
- image: forkifyRecipe,
- repo: 'https://github.com/frontendfixer/forkify-recipe-js',
- url: 'https://forkify-recipe-js.vercel.app/#5ed6604691c37cdc054bd00c',
- development: {
- language: ['javascript', 'SASS', 'MVP_Architecture', 'HTML', 'CSS'],
- },
- featured: true,
- },
- {
- id: 5,
- title: 'Electric Skateboards USA',
- description: 'This is a project 5',
- image: elctricSkateboards,
- repo: 'https://github.com/frontendfixer/electric-skateboards-USA',
- url: 'https://frontendfixer.github.io/electric-skateboards-USA/',
- development: {
- language: ['javascript', 'SASS', 'Static HTML', 'HTML', 'CSS'],
- },
- featured: true,
- },
- {
- id: 6,
- title: 'Project 6',
- description: 'This is a project 6',
- image: demoImg,
- repo: 'https://github.com',
- url: 'https://www.google.com',
- development: {
- language: ['react', 'typescript', 'HTML', 'CSS', 'redux'],
- tools: ['react', 'typescript'],
- },
- featured: false,
- },
-];
-
-export default Projects;
diff --git a/src/data/Skills.ts b/src/data/Skills.ts
deleted file mode 100644
index 8462faf..0000000
--- a/src/data/Skills.ts
+++ /dev/null
@@ -1,138 +0,0 @@
-import AwsLogo from '#assets/images/icons/aws.svg?react';
-import CodeigniterLogo from '#assets/images/icons/codeigniter.svg?react';
-import CssLogo from '#assets/images/icons/css.svg?react';
-import ExpressLogo from '#assets/images/icons/express.svg?react';
-import FigmaLogo from '#assets/images/icons/figma.svg?react';
-import GithubLogo from '#assets/images/icons/github.svg?react';
-import GoLogo from '#assets/images/icons/go.svg?react';
-import HtmlLogo from '#assets/images/icons/html.svg?react';
-import MysqlLogo from '#assets/images/icons/mysql.svg?react';
-import NestJSLogo from '#assets/images/icons/nestjs.svg?react';
-import NextjsLogo from '#assets/images/icons/nextjs.svg?react';
-import NodeJSLogo from '#assets/images/icons/nodejs.svg?react';
-import PhotoshopLogo from '#assets/images/icons/photoshop.svg?react';
-import PhpLogo from '#assets/images/icons/php.svg?react';
-import PythonLogo from '#assets/images/icons/python.svg?react';
-import ReduxLogo from '#assets/images/icons/redux.svg?react';
-import SassLogo from '#assets/images/icons/sass.svg?react';
-import TypescriptLogo from '#assets/images/icons/typescript.svg?react';
-
-type PropsType = {
- id: string;
- name: string;
- Icon: React.FunctionComponent>;
- color: string;
-};
-
-export const languages = [
- {
- id: 'nodejs',
- name: 'Nodejs',
- Icon: NodeJSLogo,
- color: '#61DBFB',
- },
- {
- id: 'typescript',
- name: 'Typescript',
- Icon: TypescriptLogo,
- color: '#61DBFB',
- },
- {
- id: 'golang',
- name: 'Go',
- Icon: GoLogo,
- color: '#61DBFB',
- },
- {
- id: 'python',
- name: 'Python',
- Icon: PythonLogo,
- color: '#61DBFB',
- },
- {
- id: 'php',
- name: 'PHP',
- Icon: PhpLogo,
- color: '#61DBFB',
- },
- {
- id: 'redux',
- name: 'Redux',
- Icon: ReduxLogo,
- color: '#61DBFB',
- },
- {
- id: 'mysql',
- name: 'MySQL',
- Icon: MysqlLogo,
- color: '#61DBFB',
- },
- {
- id: 'html5',
- name: 'HTML5',
- Icon: HtmlLogo,
- color: '#61DBFB',
- },
- {
- id: 'css3',
- name: 'CSS3',
- Icon: CssLogo,
- color: '#61DBFB',
- },
- {
- id: 'sass',
- name: 'SASS',
- Icon: SassLogo,
- color: '#61DBFB',
- },
-];
-
-export const frameworks = [
- {
- id: 'nextjs',
- name: 'Nextjs',
- Icon: NextjsLogo,
- color: '#61DBFB',
- },
- {
- id: 'nestjs',
- name: 'Nestjs',
- Icon: NestJSLogo,
- color: '#61DBFB',
- },
- {
- id: 'express',
- name: 'Express',
- Icon: ExpressLogo,
- color: '#61DBFB',
- },
- {
- id: 'codeigniter',
- name: 'Codeigniter',
- Icon: CodeigniterLogo,
- color: '#61DBFB',
- },
-];
-
-export const tools = [
- {
- id: 'aws',
- name: 'AWS Cloud',
- Icon: AwsLogo,
- },
- {
- id: 'github',
- name: 'Github',
- Icon: GithubLogo,
- },
- {
- id: 'figma',
- name: 'Figma',
- Icon: FigmaLogo,
- },
- {
- id: 'photoshop',
- name: 'PhotoShop',
- Icon: PhotoshopLogo,
- },
-];
diff --git a/src/data/Social.ts b/src/data/Social.ts
deleted file mode 100644
index a55a88d..0000000
--- a/src/data/Social.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import {
- faGithub,
- faInstagram,
- faLinkedin,
- faTwitter,
-} from '@fortawesome/free-brands-svg-icons';
-
-export type SocialLink = {
- id: number;
- name: string;
- url: string;
- icon: IconProp;
-};
-
-export const socialLinks: SocialLink[] = [
- {
- id: 1,
- name: 'GutHub',
- url: 'https://git.new/frontendfixer',
- icon: faGithub,
- },
- {
- id: 2,
- name: 'LinkedIn',
- url: 'https://dub.sh/lakshmikanta-linkedin',
- icon: faLinkedin,
- },
- {
- id: 3,
- name: 'Instagram',
- url: 'https://dub.sh/frontendfixer-insta',
- icon: faInstagram,
- },
- {
- id: 4,
- name: 'Twitter',
- url: 'https://dub.sh/frontendfixer-x',
- icon: faTwitter,
- },
-];
diff --git a/src/data/screenshot/crwn-clothing.webp b/src/data/screenshot/crwn-clothing.webp
deleted file mode 100644
index 0c67727..0000000
Binary files a/src/data/screenshot/crwn-clothing.webp and /dev/null differ
diff --git a/src/data/screenshot/electric-skateboards-USA.webp b/src/data/screenshot/electric-skateboards-USA.webp
deleted file mode 100644
index 967df4f..0000000
Binary files a/src/data/screenshot/electric-skateboards-USA.webp and /dev/null differ
diff --git a/src/data/screenshot/forkify-recipe-js.webp b/src/data/screenshot/forkify-recipe-js.webp
deleted file mode 100644
index 9e267de..0000000
Binary files a/src/data/screenshot/forkify-recipe-js.webp and /dev/null differ
diff --git a/src/data/screenshot/open-table.webp b/src/data/screenshot/open-table.webp
deleted file mode 100644
index 37cff13..0000000
Binary files a/src/data/screenshot/open-table.webp and /dev/null differ
diff --git a/src/data/screenshot/react-admin-dashboard.webp b/src/data/screenshot/react-admin-dashboard.webp
deleted file mode 100644
index e62b10f..0000000
Binary files a/src/data/screenshot/react-admin-dashboard.webp and /dev/null differ
diff --git a/src/index.css b/src/index.css
index 760f3e4..3867a13 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,199 +1,70 @@
-@import url('https://fonts.googleapis.com/css2?family=PT+Serif:wght@400;700&family=Rubik:wght@300;400;500;700&display=swap')
-layer(base);
-
+@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
@import 'tailwindcss';
-@custom-variant dark (&:is(.dark *));
-
-@utility container {
- margin-inline: auto;
-}
-
@theme {
--font-*: initial;
- --font-sans: Rubik, sans-serif;
- --font-serif: PT Serif, serif;
-
- --spacing-base: 0.75rem;
-
- --color-primary: hsl(180 100% 40%);
- --color-primary-400: hsl(180 100% 76%);
- --color-primary-500: hsl(180 90% 58%);
- --color-primary-600: hsl(180 100% 40%);
- --color-primary-700: hsl(180 80% 36%);
-
- --color-secondary: hsl(259 100% 59%);
- --color-secondary-400: hsl(259 100% 79%);
- --color-secondary-500: hsl(259 100% 69%);
- --color-secondary-600: hsl(259 100% 59%);
- --color-secondary-700: hsl(259 100% 39%);
-
- --color-white: hsl(240 21% 95%);
- --color-white-full: hsl(255 100% 100%);
-
- --color-dark: hsl(240 10% 14%);
- --color-dark-300: hsl(240 10% 84%);
- --color-dark-400: hsl(240 10% 70%);
- --color-dark-500: hsl(240 10% 50%);
- --color-dark-600: hsl(240 10% 40%);
- --color-dark-700: hsl(240 10% 30%);
- --color-dark-800: hsl(240 10% 20%);
- --color-dark-900: hsl(240 10% 14%);
-
- --animate-slideUp: slideUp 0.5s ease-in-out forwards;
- --animate-slideLeft: slideLeft 0.5s ease-in-out forwards;
- --animate-fadeIn: fadeIn 0.5s ease-in-out forwards;
- --animate-text: text 5s ease infinite alternate;
-
- @keyframes slideUp {
- 0% {
- transform: translateY(100px) scale(0.8);
- }
- 100% {
- transform: translateY(0) scale(1);
- }
- }
- @keyframes slideLeft {
- 0% {
- transform: translateX(100px) scale(1.2, 1);
- }
- 50% {
- transform: translateX(0) scale(1.3, 1);
- }
- 70% {
- transform: translateX(0) scale(1.1, 1);
- }
- 90% {
- transform: translateX(0) scale(0.9, 1);
- }
- 100% {
- transform: translateX(0) scale(1);
- }
- }
- @keyframes fadeIn {
- 0% {
- opacity: 0;
- transform: scale(0.5);
- }
- 100% {
- opacity: 1;
- transform: scale(1);
- }
- }
- @keyframes text {
- 0%,
- 100% {
- background-size: 200% 200%;
- background-position: left center;
- }
- 50% {
- background-size: 200% 200%;
- background-position: right center;
- }
- }
+ --font-sans: 'Inter', sans-serif;
+ --font-display: 'Inter', sans-serif;
+
+ --color-background: #09090B;
+ --color-secondary: #111113;
+ --color-surface: #18181B;
+ --color-border: rgba(255, 255, 255, 0.08);
+
+ --color-accent-primary: #14b8a6;
+ --color-accent-secondary: #06b6d4;
+ --color-highlight: #10b981;
+
+ --color-text-primary: #ffffff;
+ --color-text-secondary: #a1a1aa;
+ --color-text-muted: #71717a;
+
+ --radius-xl: 12px;
+ --radius-2xl: 16px;
+ --radius-3xl: 20px;
+ --radius-4xl: 24px;
+
+ --shadow-small: 0 4px 6px -1px rgba(0, 0, 0, 0.5), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
+ --shadow-medium: 0 10px 15px -3px rgba(0, 0, 0, 0.5), 0 4px 6px -2px rgba(0, 0, 0, 0.3);
+ --shadow-large: 0 20px 25px -5px rgba(0, 0, 0, 0.5), 0 10px 10px -5px rgba(0, 0, 0, 0.3);
}
-/*
- The default border color has changed to `currentcolor` in Tailwind CSS v4,
- so we've added these compatibility styles to make sure everything still
- looks the same as it did with Tailwind CSS v3.
-
- If we ever want to remove these styles, we need to add an explicit border
- color utility to any element that depends on these defaults.
-*/
@layer base {
- *,
- ::after,
- ::before,
- ::backdrop,
- ::file-selector-button {
- border-color: var(--color-gray-200, currentcolor);
+ :root {
+ color-scheme: dark;
}
-}
-
-#project-grid {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: 24px;
-}
-
-#project-grid > div {
- display: grid;
-}
-
-@media (min-width: 640px) {
- #project-grid {
- grid-template-columns: repeat(2, minmax(0, 1fr));
+ body {
+ background-color: var(--color-background);
+ color: var(--color-text-primary);
+ font-family: var(--font-sans);
+ -webkit-font-smoothing: antialiased;
+ overflow-x: hidden;
}
- #project-grid > div {
- grid-template-columns: minmax(0, 1fr);
+ ::selection {
+ background-color: rgba(20, 184, 166, 0.3);
+ color: #ffffff;
}
- #project-grid > div:nth-child(1) {
- grid-template-columns: repeat(2, minmax(0, 1fr));
- grid-column: 1/-1;
+ *, ::before, ::after {
+ border-color: var(--color-border);
}
}
-@media (min-width: 1024px) {
- #project-grid {
- grid-template-columns: repeat(6, minmax(0, 1fr));
- }
- #project-grid > div:nth-child(1),
- #project-grid > div:nth-child(2) {
- grid-template-columns: repeat(2, minmax(0, 1fr));
- }
- #project-grid > div:nth-child(1) {
- grid-column: 1/4;
- }
- #project-grid > div:nth-child(2) {
- grid-column: 4/-1;
- }
-
- #project-grid > div:nth-child(3),
- #project-grid > div:nth-child(4),
- #project-grid > div:nth-child(5) {
- grid-template-columns: minmax(0, 1fr);
- grid-template-rows: auto minmax(0, 1fr);
- }
- #project-grid > div:nth-child(3) {
- grid-column: 1/3;
+@layer utilities {
+ .text-balance {
+ text-wrap: balance;
}
- #project-grid > div:nth-child(4) {
- grid-column: 3/5;
+ .bg-grid-pattern {
+ background-image: linear-gradient(to right, rgba(255, 255, 255, 0.03) 1px, transparent 1px),
+ linear-gradient(to bottom, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
+ background-size: 24px 24px;
}
- #project-grid > div:nth-child(5) {
- grid-column: 5/-1;
+ .glass-panel {
+ background-color: rgba(24, 24, 27, 0.8);
+ backdrop-filter: blur(24px);
+ border: 1px solid var(--color-border);
+ box-shadow: var(--shadow-medium);
}
}
-
-.input__group {
- @apply relative mb-4 grid;
-}
-
-.input__group:last-child {
- @apply mb-0;
-}
-
-.input__group input,
-.input__group textarea {
- font: inherit;
- @apply border-dark-300 dark:border-dark-600 rounded-lg border bg-white px-4 py-2 outline-hidden;
-}
-
-.input__group input:focus,
-.input__group textarea:focus {
- @apply border-primary;
-}
-
-.input__group label {
- @apply pointer-events-none absolute left-4 top-2 capitalize text-gray-400 transition-all duration-300 ease-linear;
-}
-
-.input__group label.active,
-.input__group input:focus + label,
-.input__group textarea:focus + label {
- top: -1.5rem;
- font-size: 0.875rem;
- left: 0.5rem;
- @apply font-medium text-dark dark:text-white;
+html {
+ scroll-behavior: smooth;
}
diff --git a/src/lib/cn.ts b/src/lib/cn.ts
deleted file mode 100644
index 8c5ddc6..0000000
--- a/src/lib/cn.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import clsx, { ClassValue } from 'clsx';
-import { twMerge } from 'tailwind-merge';
-export const cn = (...classes: ClassValue[]) => twMerge(clsx(...classes));
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
new file mode 100644
index 0000000..9ad0df4
--- /dev/null
+++ b/src/lib/utils.ts
@@ -0,0 +1,6 @@
+import { type ClassValue, clsx } from 'clsx';
+import { twMerge } from 'tailwind-merge';
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs));
+}
diff --git a/src/main.tsx b/src/main.tsx
index c5cb173..6dca411 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -2,18 +2,17 @@ import './index.css';
import React from 'react';
import ReactDOM from 'react-dom/client';
-import { Provider } from 'react-redux';
+import { HelmetProvider } from 'react-helmet-async';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
-import { store } from './store/store';
ReactDOM.createRoot(document.getElementById('root')!).render(
-
-
+
+
-
-
+
+
,
);
diff --git a/src/routes/Home.tsx b/src/routes/Home.tsx
index edf3b27..c71abc6 100644
--- a/src/routes/Home.tsx
+++ b/src/routes/Home.tsx
@@ -1,62 +1,34 @@
-import AltHeroSection from '#components/AltHeroSection';
-import BackToTop from '#components/BackToTop';
-import Contact from '#components/Contact';
-import ContactCapsule from '#components/ContactCapsule';
-import Container from '#components/Container';
-import Footer from '#components/Footer';
-import Intro from '#components/Intro';
-// import HeroSection from '#components/HeroSection';
-import LanguageAndTool from '#components/LanguageAndTool';
-import RecentWork from '#components/RecentWork';
+import { About } from '#components/sections/About';
+import { Contact } from '#components/sections/Contact';
+import { FAQ } from '#components/sections/FAQ';
+import { FeaturedProject } from '#components/sections/FeaturedProject';
+import { Footer } from '#components/sections/Footer';
+import { HeroSection } from '#components/sections/HeroSection';
+import { Metrics } from '#components/sections/Metrics';
+import { Process } from '#components/sections/Process';
+// import { ProjectsSection } from '#components/sections/ProjectsSection';
+import { Services } from '#components/sections/Services';
+import { TechStack } from '#components/sections/TechStack';
+import { Testimonials } from '#components/sections/Testimonials';
+import { TrustStrip } from '#components/sections/TrustStrip';
const Home = () => {
return (
- <>
-
-
-
-
-
-
-
-
-
- Development Skills
-
-
-
-
-
-
-
-
-
- My recent projects
-
-
-
-
-
-
-
- >
+
+
+
+
+
+
+
+ {/* */}
+
+
+
+
+
+
+
);
};
diff --git a/src/routes/Navigation.tsx b/src/routes/Navigation.tsx
new file mode 100644
index 0000000..9cf356a
--- /dev/null
+++ b/src/routes/Navigation.tsx
@@ -0,0 +1,137 @@
+import { Menu, Terminal, X } from 'lucide-react';
+import { useEffect, useState } from 'react';
+import { Outlet } from 'react-router-dom';
+
+import { ContactButton } from '#components/sections/ContactButton.tsx';
+import { Button } from '#components/ui/Button';
+import { Container } from '#components/ui/Container';
+import { cn } from '#lib/utils';
+
+const navItems = [
+ { name: 'Services', href: '#services' },
+ { name: 'Process', href: '#process' },
+ { name: 'About', href: '#about' },
+];
+
+const Navigation = () => {
+ const [isOpen, setIsOpen] = useState(false);
+ const [scrolled, setScrolled] = useState(false);
+
+ useEffect(() => {
+ const handleScroll = () => setScrolled(window.scrollY > 20);
+ window.addEventListener('scroll', handleScroll);
+ return () => window.removeEventListener('scroll', handleScroll);
+ }, []);
+
+ useEffect(() => {
+ const handleKeyDown = (e: KeyboardEvent) => {
+ if (e.key === 'Escape') setIsOpen(false);
+ };
+ if (isOpen) window.addEventListener('keydown', handleKeyDown);
+ return () => window.removeEventListener('keydown', handleKeyDown);
+ }, [isOpen]);
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+ FrontendFixer
+
+
+
+ {/* Desktop Nav */}
+
+
+ {/* Mobile Menu Toggle */}
+ setIsOpen(!isOpen)}
+ aria-label="Toggle Menu"
+ >
+ {isOpen ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ {/* Mobile Menu Overlay */}
+
+
+
+
+ >
+ );
+};
+
+export default Navigation;
diff --git a/src/routes/Weeding.tsx b/src/routes/Weeding.tsx
deleted file mode 100644
index f8f5e3d..0000000
--- a/src/routes/Weeding.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-import { Duration, intervalToDuration } from 'date-fns';
-import { useEffect, useState } from 'react';
-import ConfettiExplosion from 'react-confetti-explosion';
-
-import Button from '#components/Button';
-import Countdown from '#components/CountDown';
-
-const Weeding = () => {
- const [password, setPassword] = useState('');
- const [isSecret, setIsSecret] = useState(false);
- const [errorMessage, setErrorMessage] = useState('');
- const [duration, setDuration] = useState(null);
- const [weedingDate] = useState(new Date(import.meta.env.VITE_WEEDING_DATE));
-
- useEffect(() => {
- const timer = setInterval(() => {
- const now = new Date();
-
- const duration = intervalToDuration({
- start: weedingDate,
- end: now,
- });
-
- setDuration(duration);
- }, 1000);
-
- return () => clearInterval(timer);
- }, [weedingDate]);
-
- const handleSubmit = (e: React.FormEvent) => {
- e.preventDefault();
- setErrorMessage('');
- const secret = import.meta.env.VITE_SECRET;
- if (password === secret) {
- setIsSecret(true);
- } else {
- setErrorMessage('Oh no! Wrong key. Try again!');
- setIsSecret(false);
- }
- };
- useEffect(() => {
- let timeoutId: NodeJS.Timeout;
- if (errorMessage) {
- timeoutId = setTimeout(() => setErrorMessage(''), 3000);
- }
- return () => clearTimeout(timeoutId);
- }, [errorMessage]);
-
- return (
-
-
- {!isSecret ? (
-
- setPassword(e.target.value)}
- className="w-full rounded-lg bg-purple-200 p-2 text-center text-5xl font-bold text-purple-800 outline-hidden placeholder:text-purple-400"
- placeholder="SECRET"
- />
-
- Enter
-
- {errorMessage && (
-
- {errorMessage}
-
- )}
-
- ) : (
-
-
- {duration && (
-
-
Days Past
-
-
- )}
-
- )}
-
-
- );
-};
-
-export default Weeding;
diff --git a/src/routes/navigation.tsx b/src/routes/navigation.tsx
deleted file mode 100644
index 0d8c62d..0000000
--- a/src/routes/navigation.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import { faBars } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { useState } from 'react';
-import { useSelector } from 'react-redux';
-import { Outlet } from 'react-router-dom';
-
-import Container from '#components/Container';
-import Logo from '#components/Logo';
-import NavigationMenu from '#components/NavigationMenu';
-import { RootState } from '#store/store';
-
-const Navigation = () => {
- const [open, setOpen] = useState(false);
- const theme = useSelector((state: RootState) => state.theme);
-
- return (
- <>
-
-
-
-
-
- setOpen(!open)}
- >
- Open main menu
-
-
-
-
-
-
-
-
- >
- );
-};
-
-export default Navigation;
diff --git a/src/store/reducer/FormSlice.ts b/src/store/reducer/FormSlice.ts
deleted file mode 100644
index 37a8a87..0000000
--- a/src/store/reducer/FormSlice.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { createSlice, PayloadAction } from '@reduxjs/toolkit';
-
-export type FormStatus = 'loading' | 'completed' | 'rejected' | undefined;
-export type FormData = { name: string; email: string; message: string };
-type InitialState = {
- data: FormData;
- status: FormStatus;
-};
-
-const initialState: InitialState = {
- data: { name: '', email: '', message: '' },
- status: undefined,
-};
-
-export const formSlice = createSlice({
- name: 'form',
- initialState: initialState,
- reducers: {
- setFormData: (data, action: PayloadAction) => {
- return { ...data, data: action.payload };
- },
- setFormStatus: (status, action: PayloadAction) => {
- return { ...status, status: action.payload };
- },
- },
-});
-
-export default formSlice.reducer;
-export const { setFormData, setFormStatus } = formSlice.actions;
diff --git a/src/store/reducer/NavigationReducer.ts b/src/store/reducer/NavigationReducer.ts
deleted file mode 100644
index c377d24..0000000
--- a/src/store/reducer/NavigationReducer.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { createSlice } from '@reduxjs/toolkit';
-
-type InitialState = {
- value: {
- isNavOpen: boolean;
- };
-};
-
-const initialState: InitialState = {
- value: {
- isNavOpen: false,
- },
-};
-
-export const navigationSlice = createSlice({
- name: 'navigation',
- initialState,
- reducers: {
- setOpen: (state: InitialState) => {
- state.value.isNavOpen = !state.value.isNavOpen;
- },
- },
-});
-
-export const { setOpen } = navigationSlice.actions;
-
-export default navigationSlice.reducer;
diff --git a/src/store/reducer/ThemeReducer.ts b/src/store/reducer/ThemeReducer.ts
deleted file mode 100644
index e9ecf26..0000000
--- a/src/store/reducer/ThemeReducer.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { createSlice } from '@reduxjs/toolkit';
-
-const getTheme = () => {
- const theme = `${window?.localStorage?.getItem('theme')}`;
- if (['light', 'dark'].includes(theme)) return theme;
-
- const userMedia = window.matchMedia('(prefers-color-scheme: light)');
- if (userMedia.matches) return 'light';
-
- return 'dark';
-};
-
-const initialState = getTheme();
-
-export const themeSlice = createSlice({
- name: 'theme',
- initialState,
- reducers: {
- toggleTheme: (_, action) => action.payload,
- },
-});
-
-export const { toggleTheme } = themeSlice.actions;
-
-export default themeSlice.reducer;
diff --git a/src/store/store.ts b/src/store/store.ts
deleted file mode 100644
index 55f3f05..0000000
--- a/src/store/store.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { configureStore } from '@reduxjs/toolkit';
-
-import formSlice from './reducer/FormSlice';
-import navigationSlice from './reducer/NavigationReducer';
-import themeSlice from './reducer/ThemeReducer';
-
-export const store = configureStore({
- reducer: {
- navigation: navigationSlice,
- theme: themeSlice,
- form: formSlice,
- },
-});
-
-export type RootState = ReturnType;
-export type AppDispatch = typeof store.dispatch;
diff --git a/tsconfig.json b/tsconfig.json
index f06579d..2c6e550 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -43,6 +43,12 @@
],
"#lib/*": [
"src/lib/*"
+ ],
+ "#config/*": [
+ "src/config/*"
+ ],
+ "#common/*": [
+ "src/components/common/*"
]
}
},