diff --git a/, b/,
deleted file mode 100644
index e69de29..0000000
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..8f70456
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,29 @@
+name: CI
+
+on:
+ push:
+ branches: [ main, master ]
+ pull_request:
+ branches: [ main, master ]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ cache: 'npm'
+
+ - name: Install dependencies
+ run: npm install
+
+ - name: Lint
+ run: npm run lint
+
+ - name: Build
+ run: npm run build
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
new file mode 100644
index 0000000..f40cdcf
--- /dev/null
+++ b/.github/workflows/deploy.yml
@@ -0,0 +1,19 @@
+name: Deploy
+
+on:
+ workflow_run:
+ workflows: ["CI"]
+ types:
+ - completed
+ branches: [main, master]
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ if: ${{ github.event.workflow_run.conclusion == 'success' }}
+ steps:
+ - name: Deploying to Production
+ run: echo "Starting deployment to production environment..."
+ # Add actual deployment steps here (e.g., Vercel, Netlify, GH Pages)
+ - name: Completion
+ run: echo "Deployment workflow triggered successfully."
diff --git a/index.html b/index.html
index c7936ed..c44ae63 100644
--- a/index.html
+++ b/index.html
@@ -7,15 +7,8 @@
-
-
-
-
-
-
-
-
-
+
+
diff --git a/package-lock.json b/package-lock.json
index 2c229a9..6639ef5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -51,6 +51,7 @@
"react": "^18.3.1",
"react-day-picker": "^8.10.1",
"react-dom": "^18.3.1",
+ "react-helmet-async": "^2.0.5",
"react-hook-form": "^7.61.1",
"react-resizable-panels": "^2.1.9",
"react-router-dom": "^6.30.1",
@@ -3013,6 +3014,7 @@
"integrity": "sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"undici-types": "~6.21.0"
}
@@ -3030,6 +3032,7 @@
"integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==",
"devOptional": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
@@ -3041,6 +3044,7 @@
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
"devOptional": true,
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"@types/react": "^18.0.0"
}
@@ -3091,6 +3095,7 @@
"integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.38.0",
"@typescript-eslint/types": "8.38.0",
@@ -3323,6 +3328,7 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -3536,6 +3542,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001726",
"electron-to-chromium": "^1.5.173",
@@ -3868,6 +3875,7 @@
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz",
"integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
"license": "MIT",
+ "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
@@ -3949,7 +3957,8 @@
"version": "8.6.0",
"resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz",
"integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/embla-carousel-react": {
"version": "8.6.0",
@@ -4050,6 +4059,7 @@
"integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -4611,6 +4621,15 @@
"node": ">=12"
}
},
+ "node_modules/invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.0.0"
+ }
+ },
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -5205,6 +5224,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -5391,6 +5411,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
@@ -5417,6 +5438,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.2"
@@ -5425,11 +5447,32 @@
"react": "^18.3.1"
}
},
+ "node_modules/react-fast-compare": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
+ "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==",
+ "license": "MIT"
+ },
+ "node_modules/react-helmet-async": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-2.0.5.tgz",
+ "integrity": "sha512-rYUYHeus+i27MvFE+Jaa4WsyBKGkL6qVgbJvSBoX8mbsWoABJXdEO0bZyi0F6i+4f0NuIb8AvqPMj3iXFHkMwg==",
+ "license": "Apache-2.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"
+ }
+ },
"node_modules/react-hook-form": {
"version": "7.61.1",
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.61.1.tgz",
"integrity": "sha512-2vbXUFDYgqEgM2RcXcAT2PwDW/80QARi+PKmHy5q2KhuKvOlG8iIYgf7eIlIANR5trW9fJbP4r5aub3a4egsew==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=18.0.0"
},
@@ -5766,6 +5809,12 @@
"node": ">=10"
}
},
+ "node_modules/shallowequal": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
+ "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==",
+ "license": "MIT"
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -5989,6 +6038,7 @@
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz",
"integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2",
@@ -6098,6 +6148,7 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -6161,6 +6212,7 @@
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"dev": true,
"license": "Apache-2.0",
+ "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -6340,6 +6392,7 @@
"integrity": "sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.5.0",
@@ -6433,6 +6486,7 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12"
},
diff --git a/package.json b/package.json
index 0378061..3b9bcc7 100644
--- a/package.json
+++ b/package.json
@@ -54,6 +54,7 @@
"react": "^18.3.1",
"react-day-picker": "^8.10.1",
"react-dom": "^18.3.1",
+ "react-helmet-async": "^2.0.5",
"react-hook-form": "^7.61.1",
"react-resizable-panels": "^2.1.9",
"react-router-dom": "^6.30.1",
diff --git a/public/avatar.jpg b/public/avatar.jpg
new file mode 100644
index 0000000..e1ea558
Binary files /dev/null and b/public/avatar.jpg differ
diff --git a/public/boy.jpg b/public/boy.jpg
new file mode 100644
index 0000000..5030590
Binary files /dev/null and b/public/boy.jpg differ
diff --git a/public/manifest.json b/public/manifest.json
new file mode 100644
index 0000000..78a92b2
--- /dev/null
+++ b/public/manifest.json
@@ -0,0 +1,20 @@
+{
+ "short_name": "NexaTech",
+ "name": "NexaTech Rwanda",
+ "icons": [
+ {
+ "src": "/favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "/og-image.png",
+ "type": "image/png",
+ "sizes": "1200x630"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#0057B8",
+ "background_color": "#ffffff"
+}
diff --git a/public/robots.txt b/public/robots.txt
new file mode 100644
index 0000000..84004df
--- /dev/null
+++ b/public/robots.txt
@@ -0,0 +1,4 @@
+User-agent: *
+Allow: /
+
+Sitemap: https://nexatech.co.rw/sitemap.xml
diff --git a/src/App.tsx b/src/App.tsx
index 9d86c2f..7da7a01 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -3,38 +3,52 @@ import { Toaster as Sonner } from "@/components/ui/sonner";
import { TooltipProvider } from "@/components/ui/tooltip";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { BrowserRouter, Routes, Route } from "react-router-dom";
+import { HelmetProvider } from "react-helmet-async";
+import React, { Suspense, lazy } from "react";
-import Index from "./pages/Index";
-import About from "./pages/About";
-import Work from "./pages/Work";
-import ShoppaDetail from "./pages/ShoppaDetail";
-import Contact from "./pages/Contact";
-import NotFound from "./pages/NotFound";
+// Lazy load pages for better performance
+const Index = lazy(() => import("./pages/Index"));
+const About = lazy(() => import("./pages/About"));
+const Work = lazy(() => import("./pages/Work"));
+const ShoppaDetail = lazy(() => import("./pages/ShoppaDetail"));
+const Contact = lazy(() => import("./pages/Contact"));
+const NotFound = lazy(() => import("./pages/NotFound"));
const queryClient = new QueryClient();
+// Loading component for Suspense
+const PageLoader = () => (
+
+);
+
const App = () => (
-
-
-
-
-
-
- {/* Home */}
- } />
+
+
+
+
+
+
+ }>
+
+ {/* Home */}
+ } />
- {/* Other pages */}
- } />
- } />
- } />
- } />
+ {/* Other pages */}
+ } />
+ } />
+ } />
+ } />
- {/* 404 – MUST stay last */}
- } />
-
-
-
-
+ {/* 404 – MUST stay last */}
+ } />
+
+
+
+
+
+
);
export default App;
diff --git a/src/components/AIChatModal.tsx b/src/components/AIChatModal.tsx
new file mode 100644
index 0000000..52d4a80
--- /dev/null
+++ b/src/components/AIChatModal.tsx
@@ -0,0 +1,151 @@
+import { useState, useRef, useEffect } from "react";
+import { motion, AnimatePresence } from "framer-motion";
+import { MessageSquare, X, Send, Bot, User } from "lucide-react";
+import { Button } from "./ui/button";
+import { Input } from "./ui/input";
+
+const AIChatModal = () => {
+ const [isOpen, setIsOpen] = useState(false);
+ const [messages, setMessages] = useState([
+ {
+ role: "bot",
+ content: "Hello! I'm NexaBot, your guide to Africa's digital future. How can I help you today?",
+ },
+ ]);
+ const [inputValue, setInputValue] = useState("");
+ const messagesEndRef = useRef(null);
+
+ const scrollToBottom = () => {
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
+ };
+
+ useEffect(() => {
+ if (isOpen) {
+ scrollToBottom();
+ }
+ }, [messages, isOpen]);
+
+ const handleSend = () => {
+ if (!inputValue.trim()) return;
+
+ const userMessage = { role: "user", content: inputValue };
+ setMessages((prev) => [...prev, userMessage]);
+ setInputValue("");
+
+ // Simulated AI Response Logic
+ setTimeout(() => {
+ let botResponse = "That's a great question! At NexaTech Rwanda, we specialize in building scalable, ready-to-market solutions for the African continent. Would you like to know more about our Custom Software, Mobile Engineering, or AI services?";
+
+ const input = userMessage.content.toLowerCase();
+ if (input.includes("who") || input.includes("nexatech")) {
+ botResponse = "NexaTech Rwanda is a product-focused technology firm based in Kigali. We architect comprehensive digital ecosystems to solve complex operational challenges and unlock new revenue streams.";
+ } else if (input.includes("service") || input.includes("what you do")) {
+ botResponse = "We provide End-to-End Digital Transformation, including Custom Enterprise Platforms, Mobile Product Engineering, and AI & Data Intelligence.";
+ } else if (input.includes("contact") || input.includes("hire") || input.includes("start")) {
+ botResponse = "You can reach us at info@nexatech.co.rw or tap the WhatsApp button on the bottom right to chat with our team directly!";
+ }
+
+ setMessages((prev) => [...prev, { role: "bot", content: botResponse }]);
+ }, 1000);
+ };
+
+ return (
+ <>
+ {/* Floating Trigger Button (Bottom Left) */}
+ setIsOpen(true)}
+ className="fixed bottom-24 right-8 z-[9999] bg-[#0057B8] text-white p-4 rounded-full shadow-[0_10px_25px_rgba(0,0,0,0.2)] flex flex-row-reverse items-center justify-center group transition-all duration-300"
+ >
+
+
+ Ask NexaBot
+
+
+
+ {/* Chat Modal */}
+
+ {isOpen && (
+
+ {/* Header */}
+
+
+
+
+
+
+
NexaBot
+
+
+ Online | AI Assistant
+
+
+
+
setIsOpen(false)}
+ className="p-2 hover:bg-white/10 rounded-full transition-colors"
+ >
+
+
+
+
+ {/* Messages Area */}
+
+ {messages.map((msg, index) => (
+
+
+
+ {msg.role === "bot" ? : }
+
+
+ {msg.content}
+
+
+
+ ))}
+
+
+
+ {/* Input Area */}
+
+
+ setInputValue(e.target.value)}
+ onKeyPress={(e) => e.key === "Enter" && handleSend()}
+ placeholder="Ask me something..."
+ className="rounded-full bg-gray-100 border-none px-6 pr-12 focus-visible:ring-1 focus-visible:ring-[#0057B8]"
+ />
+
+
+
+
+
+
+ )}
+
+ >
+ );
+};
+
+export default AIChatModal;
diff --git a/src/components/About.tsx b/src/components/About.tsx
index e70da18..d96fc84 100644
--- a/src/components/About.tsx
+++ b/src/components/About.tsx
@@ -1,9 +1,41 @@
-import { motion, useInView } from "framer-motion";
-import { useRef } from "react";
+import { motion, useInView, useSpring, useTransform } from "framer-motion";
+import { useRef, useEffect, useState } from "react";
import { Button } from "./ui/button";
import { Hand } from "lucide-react";
import { Link } from "react-router-dom";
+const Counter = ({ value, isInView }: { value: string; isInView: boolean }) => {
+ const numericPart = parseInt(value) || 0;
+ const suffix = value.replace(/[0-9]/g, "").trim();
+ const [display, setDisplay] = useState(0);
+
+ const springValue = useSpring(0, {
+ bounce: 0,
+ duration: 2000,
+ });
+
+ const displayValue = useTransform(springValue, (latest) => Math.round(latest));
+
+ useEffect(() => {
+ return displayValue.on("change", (latest) => {
+ setDisplay(latest);
+ });
+ }, [displayValue]);
+
+ useEffect(() => {
+ if (isInView) {
+ springValue.set(numericPart);
+ }
+ }, [isInView, numericPart, springValue]);
+
+ return (
+
+ {display}
+ {suffix && {suffix} }
+
+ );
+};
+
const About = () => {
const ref = useRef(null);
const isInView = useInView(ref, { once: true, margin: "-100px" });
@@ -32,10 +64,10 @@ const About = () => {
who we are
- Who Are We? The Brain Of Africa's Tech Ecosystem
+ Your Strategic Partner for Africa's Digital Backbone
- At NexaTech Rwanda, we are more than just a tech company—we are the architects of Africa's digital future.
+ NexaTech Rwanda is a product-focused technology firm based in Kigali. We don’t just write code; we architect comprehensive digital ecosystems that are ready to scale and solve Africa's most complex operational challenges.
@@ -58,9 +90,9 @@ const About = () => {
-
Africa Tech Brain
+
Ready-to-Market Innovation
- Leveraging cutting-edge technology to enhance efficiency, precision, and sustainability in every project.
+ We focus on stability, scalability, and user experience, ensuring that the solutions we build today are ready to deliver value for years to come across the continent.
@@ -105,7 +137,9 @@ const About = () => {
transition={{ duration: 0.6, delay: 0.5 + index * 0.15 }}
className="px-4"
>
- {stat.value}
+
+
+
{stat.label}
{stat.desc}
diff --git a/src/components/CTA.tsx b/src/components/CTA.tsx
index b5dcea2..90cbb02 100644
--- a/src/components/CTA.tsx
+++ b/src/components/CTA.tsx
@@ -37,7 +37,7 @@ const CTA = () => {
className="text-center"
>
- Join Africa's Tech Revolution — Start Today!
+ Join Africa's Tech Revolution Start Today!
diff --git a/src/components/FAQ.tsx b/src/components/FAQ.tsx
index 7af8856..c1b6b2d 100644
--- a/src/components/FAQ.tsx
+++ b/src/components/FAQ.tsx
@@ -116,7 +116,7 @@ const FAQ = () => {
{/* Animated Logo Carousel */}
-
+ */}
diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx
index db0087f..405a872 100644
--- a/src/components/Footer.tsx
+++ b/src/components/Footer.tsx
@@ -1,7 +1,7 @@
import { motion, useInView } from "framer-motion";
import { useRef } from "react";
import { Button } from "./ui/button";
-import { Hand, Twitter, Instagram, Linkedin } from "lucide-react";
+import { Hand, Twitter, Instagram, Linkedin, MessageSquare } from "lucide-react";
import { Link } from "react-router-dom";
const Footer = () => {
@@ -21,7 +21,7 @@ const Footer = () => {
>
NexaTech Rwanda
- Transforming Africa and Rwanda tech solutions
+ Engineering Scalable, Ready-to-Market Solutions for Africa's Future.
{
@@ -57,7 +57,7 @@ const Footer = () => {
Contacts
+250723374650
- NexaTech347@gmail.com
+ info@nexatech.co.rw
Rwanda
@@ -70,13 +70,19 @@ const Footer = () => {
transition={{ duration: 0.6, delay: 0.3 }}
className="flex flex-col md:flex-row items-center justify-between pt-8 border-t border-white/10 text-xs text-white/60"
>
- © 2025 All rights reserved
+ © 2026 All rights reserved
NexaTech Rwanda
- {[Twitter, Instagram, Linkedin].map((Icon, index) => (
+ {[
+ { Icon: Instagram, href: "https://www.instagram.com/nexa_tech.co/" },
+ { Icon: Linkedin, href: "https://www.linkedin.com/company/nexatechrwanda" },
+ { Icon: MessageSquare, href: "https://wa.me/250723374650" }
+ ].map(({ Icon, href }, index) => (
diff --git a/src/components/Hero.tsx b/src/components/Hero.tsx
index 8c4b927..03a9fe9 100644
--- a/src/components/Hero.tsx
+++ b/src/components/Hero.tsx
@@ -58,7 +58,7 @@ const Hero = () => {
className="inline-flex items-center gap-2 px-5 py-2.5 rounded-full bg-primary text-primary-foreground text-sm mb-10"
>
- Revolutionize Africa Tech
+ Building for Africa
{/* Heading */}
@@ -66,9 +66,9 @@ const Hero = () => {
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, delay: 0.4 }}
- className="font-serif text-5xl md:text-7xl lg:text-[80px] font-normal text-[#4A4A4A] mb-8 leading-[1.1] tracking-tight"
+ className="font-serif text-3xl md:text-5xl lg:text-[55px] font-normal text-[#4A4A4A] mb-8 leading-[1.1] tracking-tight"
>
- Building Africa's Tech Ecosystem From Rwanda
+ Engineering Scalable, Ready to Market Solutions for Africa's Future.
{/* Subtext */}
@@ -76,11 +76,11 @@ const Hero = () => {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.6 }}
- className="text-gray-500 text-lg md:text-xl max-w-2xl mx-auto mb-10 leading-relaxed font-light"
+ className="text-gray-500 text-md md:text-lg max-w-2xl mx-auto mb-10 leading-relaxed font-light"
>
- Transform Africa's tech with NexaTech
- Rwanda's innovative solutions. We're creating the tech ecosystem
- that will make Rwanda the brain of Africa's technological revolution.
+ We partner with visionaries to build high impact digital systems web
+ platforms, mobile applications, and AI that are engineered for the
+ African market and ready to deploy.
{/* CTA Button */}
@@ -93,7 +93,7 @@ const Hero = () => {
size="lg"
className="rounded-full bg-[#0057B8] hover:bg-[#0057B8]/90 text-white text-base px-6 py-2 h-auto shadow-[0_20px_40px_-15px_rgba(var(--primary),0.3)] hover:shadow-xl hover:-translate-y-1 transition-all duration-300 mb-5"
>
- Join Us
+ Explore Our Solutions
diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx
index 57840a8..4e9ee38 100644
--- a/src/components/Layout.tsx
+++ b/src/components/Layout.tsx
@@ -1,6 +1,8 @@
import { ReactNode } from "react";
import Navbar from "./Navbar";
import Footer from "./Footer";
+import WhatsAppButton from "./WhatsAppButton";
+import AIChatModal from "./AIChatModal";
interface LayoutProps {
children: ReactNode;
@@ -12,6 +14,8 @@ const Layout = ({ children }: LayoutProps) => {
{children}
+
+
);
};
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx
index a9ed2e5..21df632 100644
--- a/src/components/Navbar.tsx
+++ b/src/components/Navbar.tsx
@@ -1,14 +1,17 @@
import { motion } from "framer-motion";
import { CornerDownRight } from "lucide-react";
import { Button } from "./ui/button";
-import { Link } from "react-router-dom";
+import { Link, useLocation } from "react-router-dom";
const navLinks = [
- { label: "About", href: "/About" },
+ { label: "Home", href: "/" },
+ { label: "About", href: "/about" },
{ label: "Work", href: "/work" },
];
const Navbar = () => {
+ const location = useLocation();
+
return (
{
{/* Navigation Links */}
- {/* Home link */}
-
- Home
-
-
- {/* About */}
-
- About
-
-
-
- Work
-
+ {navLinks.map((link) => {
+ const isActive = location.pathname === link.href;
+ return (
+
+ {link.label}
+
+ );
+ })}
{/* Say Hi Button */}
@@ -58,7 +55,7 @@ const Navbar = () => {
className="rounded-[10px] bg-[#0057B8]/90 hover:bg-[#0057B8] text-white font-serif font-medium px-4 h-[36px] gap-2 shadow-sm transition-all duration-300 text-[13px]"
>
- Say hi
+ Get in Touch
diff --git a/src/components/SEO.tsx b/src/components/SEO.tsx
new file mode 100644
index 0000000..21c96b3
--- /dev/null
+++ b/src/components/SEO.tsx
@@ -0,0 +1,40 @@
+import { Helmet } from "react-helmet-async";
+
+interface SEOProps {
+ title?: string;
+ description?: string;
+ name?: string;
+ type?: string;
+ image?: string;
+}
+
+const SEO = ({
+ title = "NexaTech Rwanda - Building Africa's Tech Ecosystem",
+ description = "Engineering Scalable, Ready-to-Market Solutions for Africa’s Future. We architect comprehensive digital ecosystems to solve complex operational challenges.",
+ name = "NexaTech Rwanda",
+ type = "website",
+ image = "/og-image.png" // Potential future asset
+}: SEOProps) => {
+ return (
+
+ {/* Standard metadata tags */}
+ {title}
+
+
+ {/* Open Graph / Facebook */}
+
+
+
+
+
+ {/* Twitter */}
+
+
+
+
+
+
+ );
+};
+
+export default SEO;
diff --git a/src/components/Team.tsx b/src/components/Team.tsx
index c89e56f..debb167 100644
--- a/src/components/Team.tsx
+++ b/src/components/Team.tsx
@@ -25,11 +25,11 @@ const teamMembers = [
role: "Chief Marketing Officer (CMO)",
image: "./livia.png",
},
- {
- name: "Niyirera Theogene",
- role: "Chief Sales Officer (CSO)",
- image: "./munyakazi.png",
- },
+ // {
+ // name: "Niyirera Theogene",
+ // role: "Chief Sales Officer (CSO)",
+ // image: "./munyakazi.png",
+ // },
];
const Team = () => {
@@ -57,15 +57,15 @@ const Team = () => {
- {/* Team Grid */}
-
+ {/* Team Grid Row 1 */}
+
{teamMembers.slice(0, 3).map((member, index) => (
{
))}
-
+ {/* Team Grid Row 2 - Centered */}
+
{teamMembers.slice(3).map((member, index) => (
{
- Join Us
+ Start Your Project
diff --git a/src/components/WhatsAppButton.tsx b/src/components/WhatsAppButton.tsx
new file mode 100644
index 0000000..3fc2521
--- /dev/null
+++ b/src/components/WhatsAppButton.tsx
@@ -0,0 +1,28 @@
+import { motion } from "framer-motion";
+import { MessageCircle } from "lucide-react";
+
+const WhatsAppButton = () => {
+ const phoneNumber = "250723374650";
+ const message = "Hello NexaTech Rwanda, I'm interested in your services.";
+ const whatsappUrl = `https://wa.me/${phoneNumber}?text=${encodeURIComponent(message)}`;
+
+ return (
+
+
+
+ Chat on WhatsApp
+
+
+ );
+};
+
+export default WhatsAppButton;
diff --git a/src/components/WhyChooseUs.tsx b/src/components/WhyChooseUs.tsx
index f3191e9..292a2e8 100644
--- a/src/components/WhyChooseUs.tsx
+++ b/src/components/WhyChooseUs.tsx
@@ -7,18 +7,18 @@ import { Plus, Heart, Hand, Pencil } from "lucide-react";
const features = [
{
icon: Pencil,
- title: "AI-Powered Business Solutions",
- description: "We build smart automation solutions for African enterprises to Rwanda's thriving tech ecosystem.",
+ title: "Custom Enterprise Platforms",
+ description: "Tailored enterprise solutions designed to streamline complex business processes and scale across the African market.",
},
{
icon: Plus,
- title: "Custom Tech Solutions",
- description: "We design end-to-end tech solutions for Africa and Rwanda to enhance its Tech",
+ title: "Mobile Product Engineering",
+ description: "High-performance native and cross-platform mobile solutions ready for deployment and high-user engagement.",
},
{
icon: Heart,
- title: "African AI Innovation",
- description: "We are leading our africa ai innovation hub creation through our different solutions",
+ title: "AI & Data Intelligence",
+ description: "Leveraging artificial intelligence to automate workflows and provide predictive insights for smarter decision-making.",
},
];
@@ -48,11 +48,11 @@ const WhyChooseUs = () => {
className="max-w-xl"
>
- Why choose us
+ Our Ready-to-Market Solutions
- Digital Solutions for Africa
+ End-to-End Digital Transformation for Africa
diff --git a/src/components/Work.tsx b/src/components/Work.tsx
index 772a77a..1c41090 100644
--- a/src/components/Work.tsx
+++ b/src/components/Work.tsx
@@ -30,7 +30,7 @@ const Work = () => {
Our Work
- Our work speaks for itself—dive into the
+ Our work speaks for itself dive into the
projects that define us
diff --git a/src/components/ui/command.tsx b/src/components/ui/command.tsx
index 68d5378..2fe9d44 100644
--- a/src/components/ui/command.tsx
+++ b/src/components/ui/command.tsx
@@ -21,7 +21,7 @@ const Command = React.forwardRef<
));
Command.displayName = CommandPrimitive.displayName;
-interface CommandDialogProps extends DialogProps {}
+type CommandDialogProps = DialogProps
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
return (
diff --git a/src/components/ui/textarea.tsx b/src/components/ui/textarea.tsx
index 4a5643e..bf0dc97 100644
--- a/src/components/ui/textarea.tsx
+++ b/src/components/ui/textarea.tsx
@@ -2,7 +2,7 @@ import * as React from "react";
import { cn } from "@/lib/utils";
-export interface TextareaProps extends React.TextareaHTMLAttributes
{}
+export type TextareaProps = React.TextareaHTMLAttributes
const Textarea = React.forwardRef(({ className, ...props }, ref) => {
return (
diff --git a/src/pages/About.tsx b/src/pages/About.tsx
index 8951334..2ed2706 100644
--- a/src/pages/About.tsx
+++ b/src/pages/About.tsx
@@ -5,6 +5,7 @@ import { Button } from "@/components/ui/button";
import { Link } from "react-router-dom";
import { motion } from "framer-motion"
import { Lightbulb, Users, Trophy, Cpu, Rocket, Phone, Hand } from "lucide-react";
+import SEO from "@/components/SEO";
const notFoundBg = "https://images.unsplash.com/photo-1526778548025-fa2f459cd5c1";
const randomTeamLead = "https://source.unsplash.com/400x400/?person,portrait";
@@ -14,15 +15,19 @@ const About = () => {
const services = ["AI Solutions", "Cloud Solutions", "Tech Solutions", "Web Development", "Mobile Apps"];
const features = [
- { icon: Lightbulb, title: "Strategic Project Thinking", description: "We design with your business goals in mind, ensuring impactful results." },
- { icon: Users, title: "Collaborative Process", description: "We work closely with you, blending your vision with our creative expertise." },
- { icon: Trophy, title: "Proven Track Record", description: "Our success is reflected in the achievements of our satisfied clients." },
- { icon: Cpu, title: "Modern Technology", description: "Leveraging cutting-edge technology to enhance efficiency, precision, and sustainability in every project." },
+ { icon: Lightbulb, title: "Strategic Project Thinking", description: "Each digital system is architected for market readiness and scalability from day one." },
+ { icon: Users, title: "User-Centric African Architecture", description: "Solutions designed specifically for the unique needs and workflows of the African market." },
+ { icon: Trophy, title: "Scalable Pan-African Infrastructure", description: "Engineered to grow across borders, ensuring reliability as your business expands continent-wide." },
+ { icon: Cpu, title: "Local Expertise, Global Standards", description: "World-class engineering delivered with deep regional insight and market understanding." },
{ icon: Rocket, title: "Innovation Engineers", description: "A passionate team of African tech innovators dedicated to building solutions that transform entire business ecosystems across the continent." }
];
return (
+
{/* Hero Section */}
@@ -144,17 +149,18 @@ const About = () => {
{[
- { name: "Alain", role: "Developer", image: "/munyakazi.png" },
- { name: "Yvan", role: "Developer", image: "/aine.png" },
- { name: "Paola", role: "Developer", image: "/team4.png" },
-
+ { name: "Alain", role: "Developer", image: "/boy.jpg" },
+ { name: "Hope", role: "Designer", image: "/avatar.jpg" },
+ { name: "Chael", role: "Developer", image: "/boy.jpg" },
+ { name: "Corene", role: "Developer", image: "/team3.png" },
{ name: "Nikita", role: "Designer", image: "/team1.png" },
- { name: "Roger", role: "Developer", image: "/livia.png" },
+ { name: "Roger", role: "Developer", image: "/boy.jpg" },
{ name: "Nelson", role: "Developer", image: "/team2.png" },
+ { name: "Yvan", role: "Developer", image: "/boy.jpg" },
+ { name: "Paola", role: "Developer", image: "/team4.png" },
+ { name: "Jeremy", role: "Designer", image: "/boy.jpg" },
+
- { name: "Jeremy", role: "Designer", image: "/team1.png" },
- { name: "Corene", role: "Developer", image: "/team3.png" },
- { name: "Duff", role: "Developer", image: "/team5.png" },
].map((member, index) => (
{
@@ -199,7 +206,7 @@ const About = () => {
Features
- What sets us apart?
+ Built for Africa, Engineered for Impact.
Every detail counts. Discover how our tailored solutions elevate your brand,
diff --git a/src/pages/Contact.tsx b/src/pages/Contact.tsx
index 0df4337..5b92182 100644
--- a/src/pages/Contact.tsx
+++ b/src/pages/Contact.tsx
@@ -6,6 +6,7 @@ import { Textarea } from "@/components/ui/textarea";
import { Mail } from "lucide-react";
import { useToast } from "@/hooks/use-toast";
import { motion } from "framer-motion";
+import SEO from "@/components/SEO";
const Contact = () => {
const { toast } = useToast();
@@ -36,6 +37,10 @@ const Contact = () => {
return (
+
{/* Background Image */}
{
{/* Email */}
diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx
index 994e112..8030ac8 100644
--- a/src/pages/Index.tsx
+++ b/src/pages/Index.tsx
@@ -1,4 +1,4 @@
-import Navbar from "@/components/Navbar";
+import Layout from "@/components/Layout";
import Hero from "@/components/Hero";
import WhyChooseUs from "@/components/WhyChooseUs";
import Work from "@/components/Work";
@@ -7,12 +7,15 @@ import Team from "@/components/Team";
import FAQ from "@/components/FAQ";
import Testimonials from "@/components/Testimonials";
import CTA from "@/components/CTA";
-import Footer from "@/components/Footer";
+import SEO from "@/components/SEO";
const Index = () => {
return (
-
-
+
+
@@ -21,8 +24,7 @@ const Index = () => {
-
-
+
);
};
diff --git a/src/pages/ShoppaDetail.tsx b/src/pages/ShoppaDetail.tsx
index 78dc59f..1a0cb3c 100644
--- a/src/pages/ShoppaDetail.tsx
+++ b/src/pages/ShoppaDetail.tsx
@@ -1,11 +1,18 @@
import Layout from "@/components/Layout";
import { motion } from "framer-motion";
import { Button } from "@/components/ui/button";
-import { Link } from "react-router-dom";
+import { Link, useNavigate } from "react-router-dom";
+import { ArrowLeft } from "lucide-react";
+import SEO from "@/components/SEO";
const Work = () => {
+ const navigate = useNavigate();
return (
+
{/* Project Hero Section */}
@@ -19,10 +26,24 @@ const Work = () => {
+
{/* Left Column: Title & Info */}
+ {/* Back Button */}
+
navigate(-1)}
+ className="flex items-center gap-2 text-gray-400 hover:text-[#0057B8] transition-colors mb-12 group"
+ >
+
+ Back to Work
+
Shoppa
@@ -127,6 +148,7 @@ const Work = () => {
transition={{ duration: 1.5, ease: "easeOut" }}
src="/shoppa.png"
alt="Shoppa App UI"
+ loading="lazy"
className="w-full h-auto object-cover rounded-[2.5rem]"
/>
@@ -146,11 +168,11 @@ const Work = () => {
className="space-y-14"
>
- Why wait? Take the leap. Make your design process stress-free today.
+ Ready to accelerate your digital roadmap? Let's build the future of your business.
- Join Us
+ Start Your Project
diff --git a/src/pages/Work.tsx b/src/pages/Work.tsx
index 0539194..69a9379 100644
--- a/src/pages/Work.tsx
+++ b/src/pages/Work.tsx
@@ -1,6 +1,7 @@
import Layout from "@/components/Layout";
import { motion } from "framer-motion";
import { useNavigate } from "react-router-dom";
+import SEO from "@/components/SEO";
const projects = [
{
@@ -17,13 +18,17 @@ const Work = () => {
return (
+
{/* Header Section */}
- Our work speaks for itself—dive into the
+ Our work speaks for itself dive into the
projects that define us
@@ -42,7 +47,7 @@ const Work = () => {
viewport={{ once: true }}
transition={{ duration: 0.8, ease: "easeOut" }}
className="group cursor-pointer"
- onDoubleClick={() => navigate(`/work/${project.slug}`)}
+ onClick={() => navigate(`/work/${project.slug}`)}
>
{/* Image Container */}
@@ -50,6 +55,7 @@ const Work = () => {
diff --git a/tailwind.config.ts b/tailwind.config.ts
index 38f606f..19518f1 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -1,4 +1,5 @@
import type { Config } from "tailwindcss";
+import tailwindcssAnimate from "tailwindcss-animate";
export default {
darkMode: ["class"],
@@ -80,5 +81,5 @@ export default {
},
},
},
- plugins: [require("tailwindcss-animate")],
+ plugins: [tailwindcssAnimate],
} satisfies Config;