Walanja landing-page revisi
This commit is contained in:
commit
3d4709493b
|
|
@ -12,7 +12,8 @@
|
||||||
"lucide-react": "^0.541.0",
|
"lucide-react": "^0.541.0",
|
||||||
"react": "^19.1.1",
|
"react": "^19.1.1",
|
||||||
"react-dom": "^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": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.33.0",
|
"@eslint/js": "^9.33.0",
|
||||||
|
|
@ -2690,7 +2691,6 @@
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/js-yaml": {
|
"node_modules/js-yaml": {
|
||||||
|
|
@ -2820,6 +2820,18 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/lru-cache": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||||
|
|
@ -2990,7 +3002,6 @@
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
|
|
@ -3327,6 +3338,17 @@
|
||||||
"node": ">= 0.8.0"
|
"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": {
|
"node_modules/punycode": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
|
|
@ -3379,6 +3401,12 @@
|
||||||
"react": "^19.1.1"
|
"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": {
|
"node_modules/react-refresh": {
|
||||||
"version": "0.17.0",
|
"version": "0.17.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
|
||||||
|
|
@ -3427,6 +3455,19 @@
|
||||||
"react-dom": ">=18"
|
"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": {
|
"node_modules/read-cache": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,8 @@
|
||||||
"lucide-react": "^0.541.0",
|
"lucide-react": "^0.541.0",
|
||||||
"react": "^19.1.1",
|
"react": "^19.1.1",
|
||||||
"react-dom": "^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": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.33.0",
|
"@eslint/js": "^9.33.0",
|
||||||
|
|
|
||||||
BIN
public/WTell.png
BIN
public/WTell.png
Binary file not shown.
|
Before Width: | Height: | Size: 917 KiB After Width: | Height: | Size: 660 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 917 KiB |
22
src/App.jsx
22
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 Home from "./pages/Home";
|
||||||
import About from "./pages/About";
|
import About from "./pages/About";
|
||||||
import Portfolio from "./pages/Portfolio";
|
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() {
|
export default function App() {
|
||||||
return (
|
return (
|
||||||
<Router>
|
<Router>
|
||||||
|
<ScrollHandler />
|
||||||
|
<Navbar />
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Home />} />
|
<Route path="/" element={<Home />} />
|
||||||
<Route path="/about" element={<About />} />
|
<Route path="/about" element={<About />} />
|
||||||
<Route path="/portfolio" element={<Portfolio />} />
|
<Route path="/portofolio" element={<Portfolio />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1,28 +1,27 @@
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import { MapPin } from "lucide-react";
|
|
||||||
|
|
||||||
export default function Cakupan() {
|
export default function Cakupan() {
|
||||||
return (
|
return (
|
||||||
<section id="cakupan" className="relative py-20 bg-gray-50 overflow-hidden">
|
<section id="cakupan" className="relative py-20 bg-gray-50 overflow-hidden">
|
||||||
{/* Animated Gradient Background */}
|
{/* Animated Overlay */}
|
||||||
<div className="absolute inset-0 bg-gradient-to-br from-blue-50 via-white to-blue-100 animate-gradient bg-[length:300%_300%]"></div>
|
<div className="absolute inset-0 bg-gradient-to-r from-blue-50 via-white to-blue-50 animate-gradient bg-[length:300%_300%]"></div>
|
||||||
|
|
||||||
<div className="relative z-10">
|
<div className="relative z-10">
|
||||||
{/* Title */}
|
{/* Title */}
|
||||||
<div className="text-center mb-12">
|
<div className="text-center mb-12">
|
||||||
<h2 className="text-3xl md:text-4xl font-extrabold text-blue-900 drop-shadow-md">
|
<h2 className="text-3xl md:text-4xl font-bold flex items-center justify-center gap-2 text-blue-900">
|
||||||
Cakupan Area
|
Cakupan Area
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mt-3 text-gray-700 max-w-2xl mx-auto leading-relaxed">
|
<p className="mt-3 text-gray-600 max-w-2xl mx-auto">
|
||||||
Saat ini jaringan dan layanan{" "}
|
Saat ini jaringan dan layanan{" "}
|
||||||
<span className="font-semibold text-blue-600">WTELL</span> telah
|
<span className="font-semibold">WTELL</span> telah berhasil
|
||||||
berhasil menghadirkan internet di berbagai daerah di Kota Bandung
|
menghadirkan internet di berbagai daerah di Kota Bandung hingga
|
||||||
hingga Desa 3T (Tertinggal, Terdepan, Terluar).
|
Desa 3T (Tertinggal, Terdepan, Terluar).
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<div className="max-w-6xl mx-auto flex flex-col md:flex-row items-center gap-12 px-6">
|
<div className="max-w-6xl mx-auto flex flex-col md:flex-row items-stretch gap-12 px-6">
|
||||||
{/* Map */}
|
{/* Map */}
|
||||||
<motion.div
|
<motion.div
|
||||||
whileHover={{ scale: 1.05 }}
|
whileHover={{ scale: 1.05 }}
|
||||||
|
|
@ -31,38 +30,25 @@ export default function Cakupan() {
|
||||||
<img
|
<img
|
||||||
src="/map-bandung.jpg"
|
src="/map-bandung.jpg"
|
||||||
alt="Map Bandung"
|
alt="Map Bandung"
|
||||||
className="w-full max-w-xl rounded-2xl shadow-xl border-4 border-blue-100"
|
className="w-full max-w-md rounded-2xl shadow-xl border-4 border-blue-100 object-cover"
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
{/* List Area */}
|
{/* List Area */}
|
||||||
<motion.div
|
<div className="flex-1 bg-white/70 p-12 rounded-2xl shadow-lg flex flex-col justify-center">
|
||||||
whileHover={{ y: -5 }}
|
<h3 className="text-2xl text-center font-semibold mb-6 text-blue-600">
|
||||||
className="flex-1 bg-white/80 p-8 rounded-2xl shadow-xl backdrop-blur-md border border-blue-100"
|
|
||||||
>
|
|
||||||
<h3 className="text-xl font-bold mb-6 text-blue-700 border-b pb-3">
|
|
||||||
Fokus Layanan
|
Fokus Layanan
|
||||||
</h3>
|
</h3>
|
||||||
<ul className="space-y-4 text-gray-700">
|
<ul className="space-y-3 text-gray-700">
|
||||||
{[
|
<li>📍 Bandung Kota</li>
|
||||||
"Bandung Kota",
|
<li>📍 Cimahi</li>
|
||||||
"Cimahi",
|
<li>📍 Cileunyi</li>
|
||||||
"Cileunyi",
|
<li>📍 Ngamprah</li>
|
||||||
"Ngamprah",
|
<li>📍 Desa 3T sekitar Bandung</li>
|
||||||
"Desa 3T sekitar Bandung",
|
|
||||||
].map((area, index) => (
|
|
||||||
<li
|
|
||||||
key={index}
|
|
||||||
className="flex items-center gap-3 hover:bg-blue-50 p-3 rounded-lg transition"
|
|
||||||
>
|
|
||||||
<MapPin className="w-5 h-5 text-red-500" />
|
|
||||||
<span className="font-medium">{area}</span>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
</ul>
|
||||||
</motion.div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -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 (
|
||||||
|
<footer
|
||||||
|
id="footer"
|
||||||
|
ref={footerRef}
|
||||||
|
className="bg-[#5C739B] text-white py-10 px-6">
|
||||||
|
|
||||||
|
<div className="max-w-7xl mx-auto grid grid-cols-1 md:grid-cols-12 gap-8">
|
||||||
|
|
||||||
|
{/* Logo + Deskripsi */}
|
||||||
|
<div className="md:col-span-4">
|
||||||
|
<img src="/WTell.png" alt="Walanja Logo" className="w-32 mb-4" />
|
||||||
|
<p className="text-sm leading-relaxed">
|
||||||
|
PT. Jaringan Citra Mandiri adalah Perusahaan Swasta yang bergerak di bidang Penyedia
|
||||||
|
Layanan Teknologi Telekomunikasi Berbasis fiber optik.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Alamat */}
|
||||||
|
<div className="md:col-span-4">
|
||||||
|
<h3 className="font-bold text-lg mb-4 relative inline-block">
|
||||||
|
Alamat
|
||||||
|
</h3>
|
||||||
|
<p className="text-sm leading-relaxed">
|
||||||
|
Kantor Administrasi:
|
||||||
|
<br />
|
||||||
|
Jl. Paledang No. 236, Kec. Campaka, Kel. Andir Bandung 40184
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p className="text-sm leading-relaxed">
|
||||||
|
Kantor Teknis:
|
||||||
|
<br />
|
||||||
|
Parahyangan Business Park, The Suites Blok E5-E7
|
||||||
|
Jl. Soekarno Hatta No. 693, Bandung,
|
||||||
|
Jawa Barat 40286, Indonesia
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Explore */}
|
||||||
|
<div className="md:col-span-2">
|
||||||
|
<h3 className="font-bold text-lg mb-2 relative inline-block">
|
||||||
|
Explore
|
||||||
|
</h3>
|
||||||
|
<ul className="space-y-3 text-sm">
|
||||||
|
<li className="flex items-center gap-2">
|
||||||
|
<LinkIcon className="w-4 h-4" />
|
||||||
|
<Link to="/">Home</Link>
|
||||||
|
</li>
|
||||||
|
<li className="flex items-center gap-2">
|
||||||
|
<LinkIcon className="w-4 h-4" />
|
||||||
|
<Link to="/portofolio">Portofolio</Link>
|
||||||
|
</li>
|
||||||
|
<li className="flex items-center gap-2">
|
||||||
|
<LinkIcon className="w-4 h-4" />
|
||||||
|
<Link to="/about">About Us</Link>
|
||||||
|
</li>
|
||||||
|
<li className="flex items-center gap-2">
|
||||||
|
<LinkIcon className="w-4 h-4" />
|
||||||
|
<Link to="/#footer">Contact Us</Link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{/* Kontak Kami */}
|
||||||
|
<div className="md:col-span-2">
|
||||||
|
<h3 className="font-bold text-lg mb-2 relative inline-block">
|
||||||
|
Kontak Kami
|
||||||
|
</h3>
|
||||||
|
<ul className="space-y-2 text-sm">
|
||||||
|
<li className="flex items-center gap-2">
|
||||||
|
<Phone className="w-4 h-4"/> 0821 2062 3712
|
||||||
|
</li>
|
||||||
|
<li className="flex items-center gap-2">
|
||||||
|
<Mail className="w-4 h-4"/> cs@wtell.id
|
||||||
|
</li>
|
||||||
|
<li className="flex items-center gap-2">
|
||||||
|
<Earth className="w-4 h-4"/> https://www.wtell.id/
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Copyright */}
|
||||||
|
<div className="border-t border-gray-400 mt-8 pt-4 text-center text-sm">
|
||||||
|
© 2025 Walanja Telekomunikasi.
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -23,4 +23,4 @@ export default function Hero() {
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1,19 +1,24 @@
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
|
import { Menu, X } from "lucide-react";
|
||||||
import { NavLink, useLocation, useNavigate } from "react-router-dom";
|
import { NavLink, useLocation, useNavigate } from "react-router-dom";
|
||||||
|
import { HashLink } from "react-router-hash-link";
|
||||||
|
|
||||||
export default function Navbar() {
|
export default function Navbar() {
|
||||||
|
const [mobileMenu, setMobileMenu] = useState(false); // toggle mobile
|
||||||
const [scrolled, setScrolled] = useState(false);
|
const [scrolled, setScrolled] = useState(false);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
// Deteksi scroll untuk ubah background navbar
|
// Deteksi scroll untuk ubah background navbar
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleScroll = () => setScrolled(window.scrollY > 50);
|
const handleScroll = () => {
|
||||||
|
setScrolled(window.scrollY > 50);
|
||||||
|
};
|
||||||
window.addEventListener("scroll", handleScroll);
|
window.addEventListener("scroll", handleScroll);
|
||||||
return () => window.removeEventListener("scroll", handleScroll);
|
return () => window.removeEventListener("scroll", handleScroll);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Scroll otomatis kalau ada hash (#sdm, dll)
|
// Scroll otomatis kalau ada hash (#footer, dll)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (location.hash) {
|
if (location.hash) {
|
||||||
const id = location.hash.replace("#", "");
|
const id = location.hash.replace("#", "");
|
||||||
|
|
@ -26,10 +31,7 @@ export default function Navbar() {
|
||||||
}
|
}
|
||||||
}, [location]);
|
}, [location]);
|
||||||
|
|
||||||
const linkClass = ({ isActive }) =>
|
const linkClass = `block px-4 py-2 hover:text-yellow-400 transition-colors`;
|
||||||
`relative pb-1 transition-colors duration-300 hover:text-yellow-400 ${
|
|
||||||
isActive ? "text-yellow-400 font-semibold" : ""
|
|
||||||
}`;
|
|
||||||
|
|
||||||
// Klik About Us → scroll atau pindah halaman
|
// Klik About Us → scroll atau pindah halaman
|
||||||
const handleAboutClick = (e) => {
|
const handleAboutClick = (e) => {
|
||||||
|
|
@ -56,31 +58,29 @@ export default function Navbar() {
|
||||||
scrolled ? "text-black" : "text-white"
|
scrolled ? "text-black" : "text-white"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
WALANJA TELEKOMUNIKASI
|
WTELL
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Menu */}
|
{/* Menu Desktop */}
|
||||||
<ul
|
<ul
|
||||||
className={`flex items-center space-x-8 font-medium transition-colors duration-300 ${
|
className={`hidden md:flex items-center space-x-8 font-medium transition-colors duration-300 ${
|
||||||
scrolled ? "text-black" : "text-white"
|
scrolled ? "text-black" : "text-white"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{/* Home */}
|
|
||||||
<li>
|
<li>
|
||||||
<NavLink to="/" className={linkClass}>
|
<HashLink smooth to="/#" className={linkClass}>
|
||||||
Home
|
Home
|
||||||
</NavLink>
|
</HashLink>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{/* Portfolio (tanpa dropdown) */}
|
{/* Portofolio link biasa */}
|
||||||
<li>
|
<li>
|
||||||
<NavLink to="/portfolio" className={linkClass}>
|
<NavLink to="/portofolio" className={linkClass}>
|
||||||
Portfolio
|
Portofolio
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{/* About Us */}
|
|
||||||
<li>
|
<li>
|
||||||
<NavLink
|
<NavLink
|
||||||
to="/about"
|
to="/about"
|
||||||
|
|
@ -90,15 +90,82 @@ export default function Navbar() {
|
||||||
About Us
|
About Us
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{/* Contact Us */}
|
|
||||||
<li>
|
<li>
|
||||||
<NavLink to="/contact" className={linkClass}>
|
<HashLink smooth to="/#footer" className={linkClass}>
|
||||||
Contact Us
|
Contact Us
|
||||||
</NavLink>
|
</HashLink>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
{/* Hamburger Mobile */}
|
||||||
|
<button
|
||||||
|
onClick={() => setMobileMenu(!mobileMenu)}
|
||||||
|
className={`md:hidden text-2xl focus:outline-none transition-colors duration-300 ${
|
||||||
|
scrolled ? "text-black" : "text-white"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{mobileMenu ? <X /> : <Menu />}
|
||||||
|
</button>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
{/* Menu Mobile */}
|
||||||
|
{mobileMenu && (
|
||||||
|
<div
|
||||||
|
className={`md:hidden fixed top-0 right-0 w-2/3 h-screen bg-white shadow-lg z-30 transform transition-transform duration-300 ${
|
||||||
|
mobileMenu ? "translate-x-0" : "translate-x-full"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="flex justify-end p-4">
|
||||||
|
<button onClick={() => setMobileMenu(false)}>
|
||||||
|
<X size={28} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul className="flex flex-col space-y-4 px-6 font-medium text-gray-800">
|
||||||
|
<li>
|
||||||
|
<HashLink
|
||||||
|
smooth
|
||||||
|
to="/#"
|
||||||
|
onClick={() => setMobileMenu(false)}
|
||||||
|
className={linkClass}
|
||||||
|
>
|
||||||
|
Home
|
||||||
|
</HashLink>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
{/* Portofolio link biasa mobile */}
|
||||||
|
<li>
|
||||||
|
<NavLink
|
||||||
|
to="/portofolio"
|
||||||
|
onClick={() => setMobileMenu(false)}
|
||||||
|
className={linkClass}
|
||||||
|
>
|
||||||
|
Portofolio
|
||||||
|
</NavLink>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<NavLink
|
||||||
|
to="/about"
|
||||||
|
onClick={handleAboutClick}
|
||||||
|
className={linkClass}
|
||||||
|
>
|
||||||
|
About Us
|
||||||
|
</NavLink>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<HashLink
|
||||||
|
smooth
|
||||||
|
to="/#footer"
|
||||||
|
onClick={() => setMobileMenu(false)}
|
||||||
|
className={linkClass}
|
||||||
|
>
|
||||||
|
Contact Us
|
||||||
|
</HashLink>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -70,4 +70,4 @@ export default function Produk() {
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -7,4 +7,4 @@ createRoot(document.getElementById('root')).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<App />
|
<App />
|
||||||
</StrictMode>,
|
</StrictMode>,
|
||||||
)
|
)
|
||||||
|
|
@ -1,147 +1,126 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import Navbar from "../components/Navbar";
|
import Navbar from "../components/Navbar";
|
||||||
import Hero from "../components/Hero";
|
import Hero from "../components/Hero";
|
||||||
|
import Footer from "../components/Footer";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import { BadgeCheck } from "lucide-react";
|
import { CheckCircle } from "lucide-react";
|
||||||
import { useState } from "react";
|
|
||||||
|
|
||||||
export default function About() {
|
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 (
|
return (
|
||||||
<div className="font-sans">
|
<div className="font-sans">
|
||||||
{/* Navbar + Hero */}
|
{/* Navbar */}
|
||||||
<div className="relative">
|
<Navbar />
|
||||||
<Navbar />
|
|
||||||
<Hero
|
{/* Hero Section */}
|
||||||
title="Tentang Kami"
|
<Hero
|
||||||
subtitle="Kenali lebih dekat siapa kami dan visi misi kami"
|
title="Tentang Kami"
|
||||||
background="/bg-video.mp4"
|
subtitle="Kenali lebih dekat siapa kami dan visi misi kami"
|
||||||
/>
|
background="/bg-video.mp4"
|
||||||
</div>
|
/>
|
||||||
|
|
||||||
{/* About Section */}
|
{/* About Section */}
|
||||||
<section className="relative py-20 bg-gradient-to-br from-blue-50 via-white to-yellow-50 min-h-screen overflow-hidden">
|
<section className="py-20 bg-gray-50 min-h-screen">
|
||||||
{/* Dekorasi background blur */}
|
<div className="max-w-6xl mx-auto px-6 lg:px-20 space-y-16">
|
||||||
<div className="absolute top-0 left-0 w-72 h-72 bg-blue-200 rounded-full mix-blend-multiply filter blur-3xl opacity-40 animate-pulse"></div>
|
{/* Card Deskripsi Perusahaan dengan Logo */}
|
||||||
<div className="absolute bottom-0 right-0 w-96 h-96 bg-yellow-200 rounded-full mix-blend-multiply filter blur-3xl opacity-40 animate-pulse"></div>
|
|
||||||
|
|
||||||
<div className="relative max-w-6xl mx-auto px-6 lg:px-20">
|
|
||||||
{/* Logo & Deskripsi */}
|
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 40 }}
|
className="bg-white/80 backdrop-blur-lg rounded-3xl shadow-xl border border-gray-200 p-10 flex flex-col md:flex-row items-center gap-8"
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.7 }}
|
transition={{ duration: 0.7 }}
|
||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
className="bg-white/60 backdrop-blur-lg rounded-3xl shadow-2xl border border-white/20 p-10 relative z-10"
|
whileHover={{
|
||||||
|
scale: 1.02,
|
||||||
|
y: -3,
|
||||||
|
boxShadow: "0 20px 30px rgba(0,0,0,0.08)",
|
||||||
|
transition: { type: "spring", stiffness: 200, damping: 20 },
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-10 items-center">
|
{/* Logo di kiri */}
|
||||||
{/* Logo di kiri */}
|
<div className="flex justify-center md:justify-start flex-shrink-0">
|
||||||
<div className="flex justify-center">
|
<img
|
||||||
<img
|
src="/WTell_logo.png"
|
||||||
src="/WTell.png"
|
alt="Logo WTELL"
|
||||||
alt="Logo Walanja"
|
className="w-44 md:w-56"
|
||||||
className="w-64 md:w-80 drop-shadow-2xl hover:scale-105 transition-transform duration-500"
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Deskripsi di kanan */}
|
{/* Deskripsi di kanan */}
|
||||||
<div className="text-left">
|
<div className="text-center md:text-left">
|
||||||
<p className="text-gray-700 leading-relaxed text-lg">
|
<h2 className="text-3xl font-bold text-blue-700 mb-4">
|
||||||
<span className="font-semibold text-blue-700 underline decoration-blue-400 decoration-2 underline-offset-4">
|
PT. Jaringan Citra Mandiri
|
||||||
PT. Jaringan Citra Mandiri
|
</h2>
|
||||||
</span>{" "}
|
<p className="text-gray-700 leading-relaxed mb-4">
|
||||||
adalah Perusahaan Swasta yang bergerak di bidang Penyedia
|
Adalah Perusahaan Swasta yang bergerak di bidang Penyedia Layanan
|
||||||
Layanan Teknologi Telekomunikasi Berbasis Fiber Optic.
|
Teknologi Telekomunikasi Berbasis Fiber Optic.
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-4 leading-relaxed text-lg text-gray-900">
|
<p className="text-gray-700 leading-relaxed">
|
||||||
Berdiri sejak tahun 2018,{" "}
|
Berdiri sejak tahun 2018, <span className="font-semibold text-blue-700">WTELL</span>{" "}
|
||||||
<span className="font-bold text-black-700 drop-shadow-sm">
|
berkomitmen menjadi Penyedia Layanan Teknologi Telekomunikasi
|
||||||
WTELL
|
Berbasis Fiber Optic yang Handal dan Profesional.
|
||||||
</span>{" "}
|
</p>
|
||||||
berkomitmen menjadi{" "}
|
|
||||||
<span className="font-bold bg-gradient-to-r from-blue-600 to-indigo-600 bg-clip-text text-transparent">
|
|
||||||
Penyedia Layanan Teknologi Telekomunikasi Berbasis Fiber
|
|
||||||
Optic yang Handal dan Profesional
|
|
||||||
</span>
|
|
||||||
.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Visi & Misi */}
|
{/* Visi & Misi */}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-10 mt-16 relative z-10">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-10">
|
||||||
{/* Visi */}
|
{/* Visi */}
|
||||||
<motion.div
|
<motion.section
|
||||||
whileHover={{ scale: 1.04 }}
|
className="bg-white rounded-2xl p-8 cursor-pointer"
|
||||||
initial={{ opacity: 0, x: -50 }}
|
whileHover={cardHover}
|
||||||
|
initial={{ opacity: 0, x: -30 }}
|
||||||
whileInView={{ opacity: 1, x: 0 }}
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
transition={{ duration: 0.5 }}
|
transition={{ duration: 0.7 }}
|
||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
onClick={() => 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"
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<div className="relative flex flex-col items-center">
|
<h3 className="text-2xl font-bold text-center mb-6">VISI</h3>
|
||||||
<h3 className="text-3xl font-extrabold text-blue-700 tracking-wide drop-shadow-md border-b-4 border-blue-400 pb-1">
|
<p className="text-gray-700 text-center leading-relaxed">
|
||||||
VISI
|
Menjadi Penyedia Jaringan Kabel Serat Optik Terbaik yang
|
||||||
</h3>
|
Menghubungkan Seluruh Wilayah di Indonesia.
|
||||||
<p className="mt-6 leading-relaxed text-gray-800 text-lg max-w-md">
|
</p>
|
||||||
Menjadi Penyedia Jaringan Kabel Serat Optik Terbaik yang
|
</motion.section>
|
||||||
Menghubungkan Seluruh Wilayah di Indonesia.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</motion.div>
|
|
||||||
|
|
||||||
{/* Misi */}
|
{/* Misi */}
|
||||||
<motion.div
|
<motion.section
|
||||||
whileHover={{ scale: 1.04 }}
|
className="bg-white rounded-2xl p-8 cursor-pointer"
|
||||||
initial={{ opacity: 0, x: 50 }}
|
whileHover={cardHover}
|
||||||
|
initial={{ opacity: 0, x: 30 }}
|
||||||
whileInView={{ opacity: 1, x: 0 }}
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
transition={{ duration: 0.5 }}
|
transition={{ duration: 0.7 }}
|
||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
onClick={() => 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"
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<div className="relative flex flex-col items-center">
|
<h3 className="text-2xl font-bold text-center mb-6">MISI</h3>
|
||||||
<h3 className="text-3xl font-extrabold text-yellow-500 tracking-wide drop-shadow-md border-b-4 border-yellow-400 pb-1">
|
<ul className="space-y-4 text-gray-700">
|
||||||
MISI
|
<li className="flex items-start gap-2">
|
||||||
</h3>
|
<CheckCircle className="text-green-500 w-6 h-6 shrink-0 mt-1" />
|
||||||
<ul className="mt-6 space-y-4 text-gray-800 text-lg max-w-md text-left">
|
Menyediakan kebutuhan infrastruktur Kabel Serat Optik yang
|
||||||
<li className="flex items-start gap-3">
|
Handal, Terpercaya dan Up To Date dengan Tenaga Profesional.
|
||||||
<span className="bg-green-100 p-2 rounded-full">
|
</li>
|
||||||
<BadgeCheck className="text-green-600 w-6 h-6 shrink-0" />
|
<li className="flex items-start gap-2">
|
||||||
</span>
|
<CheckCircle className="text-green-500 w-6 h-6 shrink-0 mt-1" />
|
||||||
Menyediakan kebutuhan infrastruktur Kabel Serat Optik yang
|
Berkomitmen untuk berinovasi dalam teknologi jaringan Fiber
|
||||||
Handal, Terpercaya dan Up To Date dengan Tenaga Profesional.
|
Optic di seluruh Indonesia.
|
||||||
</li>
|
</li>
|
||||||
<li className="flex items-start gap-3">
|
<li className="flex items-start gap-2">
|
||||||
<span className="bg-green-100 p-2 rounded-full">
|
<CheckCircle className="text-green-500 w-6 h-6 shrink-0 mt-1" />
|
||||||
<BadgeCheck className="text-green-600 w-6 h-6 shrink-0" />
|
Memberikan nilai tambah dan sinergi dalam industri jaringan
|
||||||
</span>
|
Fiber Optic.
|
||||||
Berkomitmen untuk berinovasi dalam teknologi jaringan Fiber
|
</li>
|
||||||
Optic di seluruh Indonesia.
|
</ul>
|
||||||
</li>
|
</motion.section>
|
||||||
<li className="flex items-start gap-3">
|
|
||||||
<span className="bg-green-100 p-2 rounded-full">
|
|
||||||
<BadgeCheck className="text-green-600 w-6 h-6 shrink-0" />
|
|
||||||
</span>
|
|
||||||
Memberikan nilai tambah dan sinergi dalam industri jaringan
|
|
||||||
Fiber Optic.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</motion.div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -2,7 +2,11 @@ import Navbar from "../components/Navbar";
|
||||||
import Hero from "../components/Hero";
|
import Hero from "../components/Hero";
|
||||||
import Produk from "../components/Produk";
|
import Produk from "../components/Produk";
|
||||||
import Cakupan from "../components/Cakupan";
|
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 { motion } from "framer-motion";
|
||||||
|
import { MapPin, Wifi, Network, Cog } from "lucide-react";
|
||||||
|
|
||||||
const sectionVariant = {
|
const sectionVariant = {
|
||||||
hidden: { opacity: 0, y: 40 },
|
hidden: { opacity: 0, y: 40 },
|
||||||
|
|
@ -18,52 +22,52 @@ const sectionVariant = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
|
const footerRef = useRef(null);
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (location.hash === "#footer") {
|
||||||
|
footerRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||||
|
}
|
||||||
|
}, [location]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.div
|
<div className="font-sans">
|
||||||
className="font-sans"
|
{/* Navbar */}
|
||||||
initial={{ opacity: 0 }}
|
<Navbar />
|
||||||
animate={{ opacity: 1 }}
|
|
||||||
transition={{ duration: 0.6 }}
|
{/* Hero Section */}
|
||||||
>
|
<motion.section
|
||||||
{/* Navbar muncul pertama */}
|
|
||||||
<motion.div
|
|
||||||
variants={sectionVariant}
|
variants={sectionVariant}
|
||||||
initial="hidden"
|
initial="hidden"
|
||||||
animate="visible"
|
animate="visible"
|
||||||
custom={0.1}
|
custom={0.1}
|
||||||
>
|
>
|
||||||
<Navbar />
|
<Hero />
|
||||||
</motion.div>
|
</motion.section>
|
||||||
|
|
||||||
{/* Hero muncul kedua */}
|
{/* Produk Section */}
|
||||||
<motion.section
|
<motion.section
|
||||||
variants={sectionVariant}
|
variants={sectionVariant}
|
||||||
initial="hidden"
|
initial="hidden"
|
||||||
animate="visible"
|
animate="visible"
|
||||||
custom={0.3}
|
custom={0.3}
|
||||||
>
|
>
|
||||||
<Hero />
|
<Produk />
|
||||||
</motion.section>
|
</motion.section>
|
||||||
|
|
||||||
{/* Produk muncul ketiga */}
|
{/* Cakupan Section */}
|
||||||
<motion.section
|
<motion.section
|
||||||
variants={sectionVariant}
|
variants={sectionVariant}
|
||||||
initial="hidden"
|
initial="hidden"
|
||||||
animate="visible"
|
animate="visible"
|
||||||
custom={0.6}
|
custom={0.6}
|
||||||
>
|
|
||||||
<Produk />
|
|
||||||
</motion.section>
|
|
||||||
|
|
||||||
{/* Cakupan muncul terakhir */}
|
|
||||||
<motion.section
|
|
||||||
variants={sectionVariant}
|
|
||||||
initial="hidden"
|
|
||||||
animate="visible"
|
|
||||||
custom={0.9}
|
|
||||||
>
|
>
|
||||||
<Cakupan />
|
<Cakupan />
|
||||||
</motion.section>
|
</motion.section>
|
||||||
</motion.div>
|
|
||||||
|
{/* Footer */}
|
||||||
|
<Footer ref={footerRef} />
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import Navbar from "../components/Navbar";
|
import Navbar from "../components/Navbar";
|
||||||
|
import Footer from "../components/Footer";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
|
|
@ -47,7 +48,7 @@ export default function Portfolio() {
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
extraImages: ["/fujikura.jpg", "/yokogwa.jpg", "/exfo.jpg"], // tambahan
|
extraImages: ["/fujikura.jpg", "/yokogwa.jpg", "/exfo.jpg"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
|
|
@ -56,7 +57,6 @@ export default function Portfolio() {
|
||||||
shortDesc: "Pabrikasi tiang telco berkualitas dengan standar industri terbaik.",
|
shortDesc: "Pabrikasi tiang telco berkualitas dengan standar industri terbaik.",
|
||||||
detail: (
|
detail: (
|
||||||
<div className="space-y-10">
|
<div className="space-y-10">
|
||||||
{/* Bagian 1 */}
|
|
||||||
<div className="grid md:grid-cols-2 gap-6 items-center">
|
<div className="grid md:grid-cols-2 gap-6 items-center">
|
||||||
<img
|
<img
|
||||||
src="/tiang1.jpg"
|
src="/tiang1.jpg"
|
||||||
|
|
@ -74,7 +74,6 @@ export default function Portfolio() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Bagian 2 */}
|
|
||||||
<div className="grid md:grid-cols-2 gap-6 items-center">
|
<div className="grid md:grid-cols-2 gap-6 items-center">
|
||||||
<div className="order-2 md:order-1">
|
<div className="order-2 md:order-1">
|
||||||
<h3 className="font-semibold text-gray-800 mb-2">
|
<h3 className="font-semibold text-gray-800 mb-2">
|
||||||
|
|
@ -112,33 +111,27 @@ export default function Portfolio() {
|
||||||
Beberapa proyek utama mencakup wilayah strategis di Jawa Barat.
|
Beberapa proyek utama mencakup wilayah strategis di Jawa Barat.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Grid Lokasi */}
|
|
||||||
<div className="grid grid-cols-2 gap-4 mt-4">
|
<div className="grid grid-cols-2 gap-4 mt-4">
|
||||||
<div>
|
<div>
|
||||||
<img src="/subang.jpg" alt="Subang" className="w-full h-36 object-cover rounded-lg border" />
|
<img src="/subang.jpg" alt="Subang" className="w-full h-36 object-cover rounded-lg border" />
|
||||||
<p className="text-xs mt-1 text-center font-semibold">Subang – 50 Km</p>
|
<p className="text-xs mt-1 text-center font-semibold">Subang – 50 Km</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<img src="/pangandaran.jpg" alt="Pangandaran" className="w-full h-36 object-cover rounded-lg border" />
|
<img src="/pangandaran.jpg" alt="Pangandaran" className="w-full h-36 object-cover rounded-lg border" />
|
||||||
<p className="text-xs mt-1 text-center font-semibold">Pangandaran – 225 Km</p>
|
<p className="text-xs mt-1 text-center font-semibold">Pangandaran – 225 Km</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<img src="/bandungraya.jpg" alt="Bandung Raya" className="w-full h-36 object-cover rounded-lg border" />
|
<img src="/bandungraya.jpg" alt="Bandung Raya" className="w-full h-36 object-cover rounded-lg border" />
|
||||||
<p className="text-xs mt-1 text-center font-semibold">Bandung Raya – 800 Km</p>
|
<p className="text-xs mt-1 text-center font-semibold">Bandung Raya – 800 Km</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<img src="/garut.jpg" alt="Garut" className="w-full h-36 object-cover rounded-lg border" />
|
<img src="/garut.jpg" alt="Garut" className="w-full h-36 object-cover rounded-lg border" />
|
||||||
<p className="text-xs mt-1 text-center font-semibold">Garut – 1000 Km</p>
|
<p className="text-xs mt-1 text-center font-semibold">Garut – 1000 Km</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<img src="/ciamis.jpg" alt="Ciamis" className="w-full h-36 object-cover rounded-lg border" />
|
<img src="/ciamis.jpg" alt="Ciamis" className="w-full h-36 object-cover rounded-lg border" />
|
||||||
<p className="text-xs mt-1 text-center font-semibold">Ciamis – 100 Km</p>
|
<p className="text-xs mt-1 text-center font-semibold">Ciamis – 100 Km</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<img src="/tasik.jpg" alt="Tasik" className="w-full h-36 object-cover rounded-lg border" />
|
<img src="/tasik.jpg" alt="Tasik" className="w-full h-36 object-cover rounded-lg border" />
|
||||||
<p className="text-xs mt-1 text-center font-semibold">Tasik – 100 Km</p>
|
<p className="text-xs mt-1 text-center font-semibold">Tasik – 100 Km</p>
|
||||||
|
|
@ -151,34 +144,26 @@ export default function Portfolio() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="font-sans">
|
<div className="font-sans">
|
||||||
{/* Navbar */}
|
|
||||||
<Navbar />
|
<Navbar />
|
||||||
|
|
||||||
{/* Header Section dengan background video */}
|
<section className="relative w-full h-[400px] flex items-center justify-center text-center text-white overflow-hidden">
|
||||||
<section className="relative w-full h-[400px] flex items-center justify-center text-center text-white overflow-hidden">
|
<video
|
||||||
{/* Video background */}
|
className="absolute inset-0 w-full h-full object-cover"
|
||||||
<video
|
src="/port.mp4"
|
||||||
className="absolute inset-0 w-full h-full object-cover"
|
autoPlay
|
||||||
src="/port.mp4" // taruh video kamu di public/bg-portfolio.mp4
|
loop
|
||||||
autoPlay
|
muted
|
||||||
loop
|
playsInline
|
||||||
muted
|
/>
|
||||||
playsInline
|
<div className="absolute inset-0 bg-black/50"></div>
|
||||||
/>
|
<div className="relative z-10 px-4">
|
||||||
|
<h1 className="text-4xl font-bold mb-8">Portofolio Kami</h1>
|
||||||
|
<p className="text-lg opacity-90">
|
||||||
|
Lihat karya dan layanan terbaik yang sudah kami bangun
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
{/* Overlay gelap biar teksnya jelas */}
|
|
||||||
<div className="absolute inset-0 bg-black/50"></div>
|
|
||||||
|
|
||||||
{/* Konten teks */}
|
|
||||||
<div className="relative z-10 px-4">
|
|
||||||
<h1 className="text-4xl font-bold mb-8">Portfolio Kami</h1>
|
|
||||||
<p className="text-lg opacity-90">
|
|
||||||
Lihat karya dan layanan terbaik yang sudah kami bangun
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* Portfolio Section */}
|
|
||||||
<section className="relative py-20 bg-gradient-to-br from-indigo-50 via-white to-pink-50 min-h-screen overflow-hidden">
|
<section className="relative py-20 bg-gradient-to-br from-indigo-50 via-white to-pink-50 min-h-screen overflow-hidden">
|
||||||
<div className="relative max-w-6xl mx-auto px-6 lg:px-20">
|
<div className="relative max-w-6xl mx-auto px-6 lg:px-20">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 relative z-10">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 relative z-10">
|
||||||
|
|
@ -195,7 +180,6 @@ export default function Portfolio() {
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Modal */}
|
|
||||||
{selectedPortfolio && (
|
{selectedPortfolio && (
|
||||||
<div className="fixed inset-0 bg-black/70 flex items-center justify-center z-50 px-4">
|
<div className="fixed inset-0 bg-black/70 flex items-center justify-center z-50 px-4">
|
||||||
<motion.div
|
<motion.div
|
||||||
|
|
@ -205,7 +189,6 @@ export default function Portfolio() {
|
||||||
transition={{ duration: 0.4, ease: "easeOut" }}
|
transition={{ duration: 0.4, ease: "easeOut" }}
|
||||||
className="relative bg-white/90 backdrop-blur-xl rounded-3xl max-w-5xl w-full h-[85vh] flex flex-col shadow-2xl overflow-hidden"
|
className="relative bg-white/90 backdrop-blur-xl rounded-3xl max-w-5xl w-full h-[85vh] flex flex-col shadow-2xl overflow-hidden"
|
||||||
>
|
>
|
||||||
{/* Tombol Close */}
|
|
||||||
<button
|
<button
|
||||||
onClick={() => setSelectedPortfolio(null)}
|
onClick={() => setSelectedPortfolio(null)}
|
||||||
className="absolute top-4 right-4 z-50 bg-white/80 hover:bg-red-500 hover:text-white rounded-full shadow-md p-2 transition"
|
className="absolute top-4 right-4 z-50 bg-white/80 hover:bg-red-500 hover:text-white rounded-full shadow-md p-2 transition"
|
||||||
|
|
@ -213,7 +196,6 @@ export default function Portfolio() {
|
||||||
✕
|
✕
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{/* Gambar Header */}
|
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<img
|
<img
|
||||||
src={selectedPortfolio.image}
|
src={selectedPortfolio.image}
|
||||||
|
|
@ -228,11 +210,9 @@ export default function Portfolio() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Konten */}
|
|
||||||
<div className="p-6 overflow-y-auto flex-1 text-gray-800 space-y-4 text-sm leading-relaxed custom-scrollbar">
|
<div className="p-6 overflow-y-auto flex-1 text-gray-800 space-y-4 text-sm leading-relaxed custom-scrollbar">
|
||||||
{selectedPortfolio.detail}
|
{selectedPortfolio.detail}
|
||||||
|
|
||||||
{/* Extra Images */}
|
|
||||||
{selectedPortfolio.extraImages && (
|
{selectedPortfolio.extraImages && (
|
||||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-4 mt-6">
|
<div className="grid grid-cols-2 md:grid-cols-3 gap-4 mt-6">
|
||||||
{selectedPortfolio.extraImages.map((img, idx) => (
|
{selectedPortfolio.extraImages.map((img, idx) => (
|
||||||
|
|
@ -250,6 +230,9 @@ export default function Portfolio() {
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Tambahkan Footer */}
|
||||||
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -288,4 +271,4 @@ function PortfolioCard({ image, title, shortDesc, onClick }) {
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue