project setup
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
interface ButtonProps {
|
||||
text: string;
|
||||
}
|
||||
|
||||
const Button = ({ text }: ButtonProps) => {
|
||||
return (
|
||||
<button className="px-4 py-3 font-mono text-xs sm:text-sm text-white bg-[var(--color-3)] rounded-xl cursor-pointer">
|
||||
{text}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default Button;
|
||||
@@ -0,0 +1,19 @@
|
||||
import { ReactNode } from "react";
|
||||
|
||||
interface FeatureCardProps {
|
||||
icon: ReactNode;
|
||||
title: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
const FeatureCard = ({ icon, title, description }: FeatureCardProps) => {
|
||||
return (
|
||||
<div className="flex flex-col gap-5 border-[3px] border-[var(--color-2)] p-4 rounded-2xl">
|
||||
<div className="mb-2 bg-transparent">{icon}</div>
|
||||
<h3 className="font-mono font-bold leading-none mb-2">{title}</h3>
|
||||
<p className="text-sm sm:text-base font-mono">{description}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FeatureCard;
|
||||
@@ -0,0 +1,39 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
const Footer = () => {
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
return (
|
||||
<footer className="relative h-[125px] flex flex-col justify-center">
|
||||
<div className="absolute top-0 left-0 right-0 h-px">
|
||||
<div
|
||||
className="mx-auto w-[87.5%] h-[3px]"
|
||||
style={{
|
||||
background: "var(--color-2)",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mx-8 flex flex-col md:flex-row justify-between items-center relative">
|
||||
<div className="mb-4 md:mb-0">
|
||||
<Link href="/">
|
||||
<Image
|
||||
src="/assets/images/logo_no_bg.png"
|
||||
alt="Logo"
|
||||
width={125}
|
||||
height={125}
|
||||
className="w-[100px] h-auto sm:w-[120px] lg:w-[125px]"
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="text-white text-sm font-mono absolute top-[70%] md:static left-0 right-0 text-center md:text-right">
|
||||
{currentYear} Lan Codes All Rights Reserved
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Footer;
|
||||
@@ -0,0 +1,31 @@
|
||||
import Image, { StaticImageData } from "next/image";
|
||||
|
||||
interface TeamMemberCardProps {
|
||||
avatar: StaticImageData;
|
||||
name: string;
|
||||
position: string;
|
||||
}
|
||||
|
||||
const TeamMemberCard = ({ avatar, name, position }: TeamMemberCardProps) => {
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-3">
|
||||
<div className="relative w-40 h-40 sm:w-48 sm:h-48 rounded-full border-2 overflow-hidden">
|
||||
<Image src={avatar} alt={name} className="object-cover" />
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p
|
||||
className={`font-mono text-sm ${
|
||||
position === "Founder" ? "text-white" : "text-[var(--color-7)]"
|
||||
}`}
|
||||
>
|
||||
{name}
|
||||
</p>
|
||||
{position !== "Founder" && (
|
||||
<p className="font-mono text-sm text-[var(--color-10)]">{position}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TeamMemberCard;
|
||||
@@ -0,0 +1,17 @@
|
||||
import Link from "next/link";
|
||||
|
||||
import Button from "@/components/Button";
|
||||
|
||||
interface GetStartedButtonProps {
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const GetStartedButton = ({ onClick }: GetStartedButtonProps) => {
|
||||
return (
|
||||
<Link href="/get-started" onClick={onClick}>
|
||||
<Button text="Get Started" />
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export default GetStartedButton;
|
||||
@@ -0,0 +1,51 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
interface NavLinksProps {
|
||||
mobile?: boolean;
|
||||
onLinkClick?: () => void;
|
||||
}
|
||||
|
||||
const NavLinks = ({ mobile = false, onLinkClick }: NavLinksProps) => {
|
||||
const pathname = usePathname();
|
||||
|
||||
const containerClass = mobile
|
||||
? "flex flex-col items-center gap-4 text-lg min-[828px]:flex-row min-[828px]:gap-6"
|
||||
: "hidden md:flex items-center gap-8 text-lg";
|
||||
|
||||
return (
|
||||
<nav className={containerClass}>
|
||||
<Link href="/services" onClick={onLinkClick}>
|
||||
<span
|
||||
className={`${
|
||||
pathname === "/services" && "text-[var(--color-8)]"
|
||||
} font-mono`}
|
||||
>
|
||||
Service
|
||||
</span>
|
||||
</Link>
|
||||
<Link href="/about" onClick={onLinkClick}>
|
||||
<span
|
||||
className={`${
|
||||
pathname === "/about" && "text-[var(--color-8)]"
|
||||
} font-mono`}
|
||||
>
|
||||
About us
|
||||
</span>
|
||||
</Link>
|
||||
<Link href="/contact" onClick={onLinkClick}>
|
||||
<span
|
||||
className={`${
|
||||
pathname === "/contact" && "text-[var(--color-8)]"
|
||||
} font-mono`}
|
||||
>
|
||||
Contact
|
||||
</span>
|
||||
</Link>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavLinks;
|
||||
@@ -0,0 +1,80 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { Menu, X } from "lucide-react";
|
||||
|
||||
import NavLinks from "@/components/navigation/NavLinks";
|
||||
import SiteLogo from "@/components/navigation/SiteLogo";
|
||||
import GetStartedButton from "@/components/navigation/GetStartedButton";
|
||||
|
||||
const Navbar = () => {
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
const pathname = usePathname();
|
||||
|
||||
const isGetStartedPage = pathname === "/get-started";
|
||||
const isHeroOrAboutPage = pathname === "/" || pathname === "/about";
|
||||
const isAboutPage = pathname === "/about";
|
||||
|
||||
return (
|
||||
<header
|
||||
className={`relative z-50 ${
|
||||
isHeroOrAboutPage ? "bg-transparent" : "bg-[var(--color-1)]"
|
||||
}`}
|
||||
>
|
||||
<nav className="flex items-center h-[75px] px-6 md:px-12 relative">
|
||||
<div className="flex-shrink-0" onClick={() => setMenuOpen(false)}>
|
||||
<SiteLogo />
|
||||
</div>
|
||||
|
||||
<div className="hidden min-[828px]:flex min-[870px]:hidden items-center gap-6 ml-auto">
|
||||
<NavLinks mobile={true} onLinkClick={() => setMenuOpen(false)} />
|
||||
{!isGetStartedPage && <GetStartedButton />}
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={`hidden min-[870px]:flex ${
|
||||
isGetStartedPage
|
||||
? "absolute left-1/2 transform -translate-x-1/2"
|
||||
: "flex-1 justify-center transform -translate-x-[7.5%]"
|
||||
}`}
|
||||
>
|
||||
<NavLinks onLinkClick={() => setMenuOpen(false)} />
|
||||
</div>
|
||||
|
||||
<div className="hidden min-[870px]:flex flex-shrink-0">
|
||||
{!isGetStartedPage && <GetStartedButton />}
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => setMenuOpen(!menuOpen)}
|
||||
className="min-[828px]:hidden absolute right-6 top-1/2 transform -translate-y-1/2 p-2 text-[var(--color-8)]"
|
||||
aria-label="Toggle menu"
|
||||
>
|
||||
{menuOpen ? <X size={26} /> : <Menu size={26} />}
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
{menuOpen && (
|
||||
<div className="min-[828px]:hidden bg-[var(--color-1)] border-t border-[var(--color-2)]">
|
||||
<div className="flex flex-col items-center py-4 space-y-4">
|
||||
<NavLinks mobile={true} onLinkClick={() => setMenuOpen(false)} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div
|
||||
className="absolute left-0 right-0 h-[3px] mx-auto w-[87.5%]"
|
||||
style={{
|
||||
background: `${
|
||||
isAboutPage
|
||||
? "color-mix(in srgb, var(--color-2) 50%, transparent)"
|
||||
: "var(--color-2)"
|
||||
}`,
|
||||
}}
|
||||
/>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
export default Navbar;
|
||||
@@ -0,0 +1,31 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
const SiteLogo = () => {
|
||||
return (
|
||||
<Link href="/" className="flex items-center gap-1">
|
||||
<div
|
||||
className="relative overflow-hidden w-[100px] h-[100px] sm:w-[120px] sm:h-[120px] lg:w-[150px] lg:h-[150px]"
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src="/assets/images/logo_no_bg.png"
|
||||
alt="Logo"
|
||||
width={150}
|
||||
height={150}
|
||||
priority
|
||||
style={{ objectFit: "contain", marginTop: 4 }}
|
||||
/>
|
||||
</div>
|
||||
<span className="font-mono text-xl sm:text-2xl lg:text-3xl z-100">
|
||||
LAN CODES
|
||||
</span>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export default SiteLogo;
|
||||
@@ -0,0 +1,17 @@
|
||||
import { ToastContainer } from "react-toastify";
|
||||
import "react-toastify/dist/ReactToastify.css";
|
||||
|
||||
const ToastProvider = () => {
|
||||
return (
|
||||
<ToastContainer
|
||||
position="bottom-right"
|
||||
autoClose={3000}
|
||||
newestOnTop
|
||||
closeOnClick
|
||||
pauseOnHover={false}
|
||||
theme="colored"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ToastProvider;
|
||||
@@ -0,0 +1,43 @@
|
||||
import { ProjectItem } from "@/data/StaticData";
|
||||
|
||||
interface ProjectItemsProps {
|
||||
items: ProjectItem[];
|
||||
activeIndex: number;
|
||||
setActiveIndex: (idx: number) => void;
|
||||
}
|
||||
|
||||
const ProjectItems = ({
|
||||
items,
|
||||
activeIndex,
|
||||
setActiveIndex,
|
||||
}: ProjectItemsProps) => {
|
||||
return (
|
||||
<ul className="space-y-8">
|
||||
{items.map(({ title }, idx) => {
|
||||
const isActive = idx === activeIndex;
|
||||
|
||||
return (
|
||||
<li key={title}>
|
||||
<button
|
||||
onClick={() => setActiveIndex(idx)}
|
||||
className={`ml-1 w-full text-left flex items-center gap-4 rounded-md px-2 py-2 transition cursor-pointer ${
|
||||
isActive && "bg-[var(--color-2)] md:rounded-r-none"
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className={`inline-block w-3.5 h-3.5 rotate-45 ${
|
||||
isActive
|
||||
? "bg-[var(--color-8)] shadow-[0_0_10px_rgba(127,17,224,1)]"
|
||||
: "bg-[var(--color-10)]"
|
||||
}`}
|
||||
/>
|
||||
<span className="font-mono text-sm sm:text-base">{title}</span>
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectItems;
|
||||
Reference in New Issue
Block a user