diff --git a/package-lock.json b/package-lock.json index c037948..d0a2720 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,8 @@ "lucide-react": "^0.541.0", "react": "^19.1.1", "react-dom": "^19.1.1", - "react-router-dom": "^7.8.2" + "react-router-dom": "^7.8.2", + "react-router-hash-link": "^2.4.3" }, "devDependencies": { "@eslint/js": "^9.33.0", @@ -2690,7 +2691,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -2820,6 +2820,18 @@ "dev": true, "license": "MIT" }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -2990,7 +3002,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3327,6 +3338,17 @@ "node": ">= 0.8.0" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -3379,6 +3401,12 @@ "react": "^19.1.1" } }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/react-refresh": { "version": "0.17.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", @@ -3427,6 +3455,19 @@ "react-dom": ">=18" } }, + "node_modules/react-router-hash-link": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/react-router-hash-link/-/react-router-hash-link-2.4.3.tgz", + "integrity": "sha512-NU7GWc265m92xh/aYD79Vr1W+zAIXDWp3L2YZOYP4rCqPnJ6LI6vh3+rKgkidtYijozHclaEQTAHaAaMWPVI4A==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": ">=15", + "react-router-dom": ">=4" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", diff --git a/package.json b/package.json index 7fafcbd..01413f2 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "lucide-react": "^0.541.0", "react": "^19.1.1", "react-dom": "^19.1.1", - "react-router-dom": "^7.8.2" + "react-router-dom": "^7.8.2", + "react-router-hash-link": "^2.4.3" }, "devDependencies": { "@eslint/js": "^9.33.0", diff --git a/public/WTell.png b/public/WTell.png index db262e9..f57d06e 100644 Binary files a/public/WTell.png and b/public/WTell.png differ diff --git a/public/WTell_logo.png b/public/WTell_logo.png new file mode 100644 index 0000000..db262e9 Binary files /dev/null and b/public/WTell_logo.png differ diff --git a/src/App.jsx b/src/App.jsx index 63012ce..1acd92d 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,16 +1,32 @@ -import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; +import { BrowserRouter as Router, Routes, Route, useLocation } from "react-router-dom"; +import { useEffect } from "react"; +import Navbar from "./components/Navbar"; import Home from "./pages/Home"; import About from "./pages/About"; import Portfolio from "./pages/Portfolio"; + +function ScrollHandler() { + const { pathname } = useLocation(); + + useEffect(() => { + // tiap kali route berubah, scroll ke atas + window.scrollTo(0, 0); + }, [pathname]); + + return null; +} + export default function App() { return ( + + } /> } /> - } /> + } /> ); -} +} \ No newline at end of file diff --git a/src/components/Cakupan.jsx b/src/components/Cakupan.jsx index 8441a55..41b4feb 100644 --- a/src/components/Cakupan.jsx +++ b/src/components/Cakupan.jsx @@ -1,28 +1,27 @@ import { motion } from "framer-motion"; -import { MapPin } from "lucide-react"; export default function Cakupan() { return (
- {/* Animated Gradient Background */} -
+ {/* Animated Overlay */} +
{/* Title */}
-

+

Cakupan Area

-

+

Saat ini jaringan dan layanan{" "} - WTELL telah - berhasil menghadirkan internet di berbagai daerah di Kota Bandung - hingga Desa 3T (Tertinggal, Terdepan, Terluar). + WTELL telah berhasil + menghadirkan internet di berbagai daerah di Kota Bandung hingga + Desa 3T (Tertinggal, Terdepan, Terluar).

{/* Content */} -
+
{/* Map */} {/* List Area */} - -

+
+

Fokus Layanan

-
    - {[ - "Bandung Kota", - "Cimahi", - "Cileunyi", - "Ngamprah", - "Desa 3T sekitar Bandung", - ].map((area, index) => ( -
  • - - {area} -
  • - ))} +
      +
    • 📍 Bandung Kota
    • +
    • 📍 Cimahi
    • +
    • 📍 Cileunyi
    • +
    • 📍 Ngamprah
    • +
    • 📍 Desa 3T sekitar Bandung
    - +

); -} +} \ No newline at end of file diff --git a/src/components/Footer.jsx b/src/components/Footer.jsx new file mode 100644 index 0000000..25c71d7 --- /dev/null +++ b/src/components/Footer.jsx @@ -0,0 +1,94 @@ +import { Phone, Mail, Earth, Link as LinkIcon } from "lucide-react"; +import { Link } from "react-router-dom"; // ini untuk routing + +export default function Footer({ footerRef }) { + return ( + + ); +} \ No newline at end of file diff --git a/src/components/Hero.jsx b/src/components/Hero.jsx index 4b28cac..50f79a8 100644 --- a/src/components/Hero.jsx +++ b/src/components/Hero.jsx @@ -23,4 +23,4 @@ export default function Hero() { ); -} +} \ No newline at end of file diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx index d487e3c..714e0a3 100644 --- a/src/components/Navbar.jsx +++ b/src/components/Navbar.jsx @@ -1,19 +1,24 @@ import { useState, useEffect } from "react"; +import { Menu, X } from "lucide-react"; import { NavLink, useLocation, useNavigate } from "react-router-dom"; +import { HashLink } from "react-router-hash-link"; export default function Navbar() { + const [mobileMenu, setMobileMenu] = useState(false); // toggle mobile const [scrolled, setScrolled] = useState(false); const location = useLocation(); const navigate = useNavigate(); // Deteksi scroll untuk ubah background navbar useEffect(() => { - const handleScroll = () => setScrolled(window.scrollY > 50); + const handleScroll = () => { + setScrolled(window.scrollY > 50); + }; window.addEventListener("scroll", handleScroll); return () => window.removeEventListener("scroll", handleScroll); }, []); - // Scroll otomatis kalau ada hash (#sdm, dll) + // Scroll otomatis kalau ada hash (#footer, dll) useEffect(() => { if (location.hash) { const id = location.hash.replace("#", ""); @@ -26,10 +31,7 @@ export default function Navbar() { } }, [location]); - const linkClass = ({ isActive }) => - `relative pb-1 transition-colors duration-300 hover:text-yellow-400 ${ - isActive ? "text-yellow-400 font-semibold" : "" - }`; + const linkClass = `block px-4 py-2 hover:text-yellow-400 transition-colors`; // Klik About Us → scroll atau pindah halaman const handleAboutClick = (e) => { @@ -56,31 +58,29 @@ export default function Navbar() { scrolled ? "text-black" : "text-white" }`} > - WALANJA TELEKOMUNIKASI + WTELL - {/* Menu */} + {/* Menu Desktop */} + + {/* Hamburger Mobile */} + + + {/* Menu Mobile */} + {mobileMenu && ( +
+
+ +
+ + +
+ )} ); -} +} \ No newline at end of file diff --git a/src/components/Produk.jsx b/src/components/Produk.jsx index 13a5016..d9be363 100644 --- a/src/components/Produk.jsx +++ b/src/components/Produk.jsx @@ -70,4 +70,4 @@ export default function Produk() { ); -} +} \ No newline at end of file diff --git a/src/main.jsx b/src/main.jsx index b9a1a6d..9347e15 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -7,4 +7,4 @@ createRoot(document.getElementById('root')).render( , -) +) \ No newline at end of file diff --git a/src/pages/About.jsx b/src/pages/About.jsx index 59037a4..a6ef1e7 100644 --- a/src/pages/About.jsx +++ b/src/pages/About.jsx @@ -1,147 +1,126 @@ +"use client"; + import Navbar from "../components/Navbar"; import Hero from "../components/Hero"; +import Footer from "../components/Footer"; import { motion } from "framer-motion"; -import { BadgeCheck } from "lucide-react"; -import { useState } from "react"; +import { CheckCircle } from "lucide-react"; export default function About() { - const [activeCard, setActiveCard] = useState(null); + const cardHover = { + scale: 1.03, + y: -4, + boxShadow: "0 15px 25px rgba(0,0,0,0.1)", + transition: { type: "spring", stiffness: 200, damping: 20 }, + }; return (
- {/* Navbar + Hero */} -
- - -
+ {/* Navbar */} + + + {/* Hero Section */} + {/* About Section */} -
- {/* Dekorasi background blur */} -
-
- -
- {/* Logo & Deskripsi */} +
+
+ {/* Card Deskripsi Perusahaan dengan Logo */} -
- {/* Logo di kiri */} -
- Logo Walanja -
+ {/* Logo di kiri */} +
+ Logo WTELL +
- {/* Deskripsi di kanan */} -
-

- - PT. Jaringan Citra Mandiri - {" "} - adalah Perusahaan Swasta yang bergerak di bidang Penyedia - Layanan Teknologi Telekomunikasi Berbasis Fiber Optic. -

-

- Berdiri sejak tahun 2018,{" "} - - WTELL - {" "} - berkomitmen menjadi{" "} - - Penyedia Layanan Teknologi Telekomunikasi Berbasis Fiber - Optic yang Handal dan Profesional - - . -

-
+ {/* Deskripsi di kanan */} +
+

+ PT. Jaringan Citra Mandiri +

+

+ Adalah Perusahaan Swasta yang bergerak di bidang Penyedia Layanan + Teknologi Telekomunikasi Berbasis Fiber Optic. +

+

+ Berdiri sejak tahun 2018, WTELL{" "} + berkomitmen menjadi Penyedia Layanan Teknologi Telekomunikasi + Berbasis Fiber Optic yang Handal dan Profesional. +

{/* Visi & Misi */} -
+
{/* Visi */} - setActiveCard("visi")} - className={`relative rounded-3xl bg-white p-10 overflow-hidden flex flex-col items-center text-center cursor-pointer transition-all duration-200 ease-out hover:shadow-2xl hover:-translate-y-2 hover:rotate-[1deg] ${ - activeCard === "visi" - ? "border-4 border-blue-500 shadow-blue-300" - : "border border-gray-200" - }`} > -
-

- VISI -

-

- Menjadi Penyedia Jaringan Kabel Serat Optik Terbaik yang - Menghubungkan Seluruh Wilayah di Indonesia. -

-
-
+

VISI

+

+ Menjadi Penyedia Jaringan Kabel Serat Optik Terbaik yang + Menghubungkan Seluruh Wilayah di Indonesia. +

+ {/* Misi */} - setActiveCard("misi")} - className={`relative rounded-3xl bg-white p-10 overflow-hidden flex flex-col items-center text-center cursor-pointer transition-all duration-200 ease-out hover:shadow-2xl hover:-translate-y-2 hover:rotate-[1deg] ${ - activeCard === "misi" - ? "border-4 border-blue-500 shadow-blue-300" - : "border border-gray-200" - }`} > -
-

- MISI -

-
    -
  • - - - - Menyediakan kebutuhan infrastruktur Kabel Serat Optik yang - Handal, Terpercaya dan Up To Date dengan Tenaga Profesional. -
  • -
  • - - - - Berkomitmen untuk berinovasi dalam teknologi jaringan Fiber - Optic di seluruh Indonesia. -
  • -
  • - - - - Memberikan nilai tambah dan sinergi dalam industri jaringan - Fiber Optic. -
  • -
-
-
+

MISI

+
    +
  • + + Menyediakan kebutuhan infrastruktur Kabel Serat Optik yang + Handal, Terpercaya dan Up To Date dengan Tenaga Profesional. +
  • +
  • + + Berkomitmen untuk berinovasi dalam teknologi jaringan Fiber + Optic di seluruh Indonesia. +
  • +
  • + + Memberikan nilai tambah dan sinergi dalam industri jaringan + Fiber Optic. +
  • +
+
+ + {/* Footer */} +
); -} +} \ No newline at end of file diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index 73d3658..cb73b64 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -2,7 +2,11 @@ import Navbar from "../components/Navbar"; import Hero from "../components/Hero"; import Produk from "../components/Produk"; import Cakupan from "../components/Cakupan"; +import Footer from "../components/Footer"; +import { useEffect, useRef } from "react"; +import { useLocation } from "react-router-dom"; import { motion } from "framer-motion"; +import { MapPin, Wifi, Network, Cog } from "lucide-react"; const sectionVariant = { hidden: { opacity: 0, y: 40 }, @@ -18,52 +22,52 @@ const sectionVariant = { }; export default function Home() { + const footerRef = useRef(null); + const location = useLocation(); + + useEffect(() => { + if (location.hash === "#footer") { + footerRef.current?.scrollIntoView({ behavior: "smooth" }); + } + }, [location]); + return ( - - {/* Navbar muncul pertama */} - + {/* Navbar */} + + + {/* Hero Section */} + - - + + - {/* Hero muncul kedua */} + {/* Produk Section */} - + - {/* Produk muncul ketiga */} + {/* Cakupan Section */} - - - - {/* Cakupan muncul terakhir */} - - + + {/* Footer */} +
); } \ No newline at end of file diff --git a/src/pages/Portfolio.jsx b/src/pages/Portfolio.jsx index d478c72..4e19162 100644 --- a/src/pages/Portfolio.jsx +++ b/src/pages/Portfolio.jsx @@ -1,4 +1,5 @@ import Navbar from "../components/Navbar"; +import Footer from "../components/Footer"; import { motion } from "framer-motion"; import { useState } from "react"; @@ -47,7 +48,7 @@ export default function Portfolio() {

), - extraImages: ["/fujikura.jpg", "/yokogwa.jpg", "/exfo.jpg"], // tambahan + extraImages: ["/fujikura.jpg", "/yokogwa.jpg", "/exfo.jpg"], }, { id: 3, @@ -56,7 +57,6 @@ export default function Portfolio() { shortDesc: "Pabrikasi tiang telco berkualitas dengan standar industri terbaik.", detail: (
- {/* Bagian 1 */}
- {/* Bagian 2 */}

@@ -112,33 +111,27 @@ export default function Portfolio() { Beberapa proyek utama mencakup wilayah strategis di Jawa Barat.

- {/* Grid Lokasi */}
Subang

Subang – 50 Km

-
Pangandaran

Pangandaran – 225 Km

-
Bandung Raya

Bandung Raya – 800 Km

-
Garut

Garut – 1000 Km

-
Ciamis

Ciamis – 100 Km

-
Tasik

Tasik – 100 Km

@@ -151,34 +144,26 @@ export default function Portfolio() { return (
- {/* Navbar */} - {/* Header Section dengan background video */} -
- {/* Video background */} -
- - {/* Portfolio Section */}
@@ -195,7 +180,6 @@ export default function Portfolio() {
- {/* Modal */} {selectedPortfolio && (
- {/* Tombol Close */} - {/* Gambar Header */}
- {/* Konten */}
{selectedPortfolio.detail} - {/* Extra Images */} {selectedPortfolio.extraImages && (
{selectedPortfolio.extraImages.map((img, idx) => ( @@ -250,6 +230,9 @@ export default function Portfolio() {
)} + + {/* Tambahkan Footer */} +
); } @@ -288,4 +271,4 @@ function PortfolioCard({ image, title, shortDesc, onClick }) {
); -} +} \ No newline at end of file