1405 lines
32 KiB
HTML
1405 lines
32 KiB
HTML
<!doctype html>
|
|
<html lang="id">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta
|
|
name="viewport"
|
|
content="width=device-width, initial-scale=1.0"
|
|
/>
|
|
<title>WebGIS — Sistem Informasi Geografis | Portofolio Tugas</title>
|
|
<meta
|
|
name="description"
|
|
content="Portofolio proyek WebGIS mata kuliah Sistem Informasi Geografis. Kumpulan aplikasi pemetaan interaktif berbasis web menggunakan Leaflet.js, PHP, dan MySQL."
|
|
/>
|
|
<link
|
|
rel="preconnect"
|
|
href="https://fonts.googleapis.com"
|
|
/>
|
|
<link
|
|
rel="preconnect"
|
|
href="https://fonts.gstatic.com"
|
|
crossorigin
|
|
/>
|
|
<link
|
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=Space+Grotesk:wght@400;500;600;700&display=swap"
|
|
rel="stylesheet"
|
|
/>
|
|
<link
|
|
rel="stylesheet"
|
|
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
|
|
/>
|
|
<style>
|
|
/* ===== CSS RESET & BASE ===== */
|
|
*,
|
|
*::before,
|
|
*::after {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
:root {
|
|
--clr-bg: #f0f4f8;
|
|
--clr-surface: #e8eef5;
|
|
--clr-card: #ffffff;
|
|
--clr-border: rgba(99, 102, 241, 0.15);
|
|
--clr-primary: #4f46e5;
|
|
--clr-secondary: #7c3aed;
|
|
--clr-accent: #059669;
|
|
--clr-warn: #ea580c;
|
|
--clr-text: #1e293b;
|
|
--clr-muted: #64748b;
|
|
--clr-white: #ffffff;
|
|
--grad-primary: linear-gradient(135deg, #4f46e5, #7c3aed);
|
|
--grad-card: linear-gradient(145deg, #ffffff, #f8fafc);
|
|
--shadow-glow: 0 0 40px rgba(79, 70, 229, 0.1);
|
|
--shadow-card: 0 4px 24px rgba(15, 23, 42, 0.08);
|
|
--radius: 16px;
|
|
--radius-sm: 10px;
|
|
--transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
|
|
}
|
|
|
|
html {
|
|
scroll-behavior: smooth;
|
|
}
|
|
|
|
body {
|
|
font-family: "Inter", sans-serif;
|
|
background-color: var(--clr-bg);
|
|
color: var(--clr-text);
|
|
line-height: 1.6;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
/* ===== SCROLLBAR ===== */
|
|
::-webkit-scrollbar {
|
|
width: 6px;
|
|
}
|
|
::-webkit-scrollbar-track {
|
|
background: var(--clr-bg);
|
|
}
|
|
::-webkit-scrollbar-thumb {
|
|
background: var(--clr-primary);
|
|
border-radius: 3px;
|
|
}
|
|
|
|
/* ===== CANVAS BG ===== */
|
|
#bg-canvas {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
z-index: 0;
|
|
pointer-events: none;
|
|
opacity: 0.5;
|
|
}
|
|
|
|
/* ===== LAYOUT ===== */
|
|
.wrapper {
|
|
position: relative;
|
|
z-index: 1;
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 0 24px;
|
|
}
|
|
|
|
/* ===== NAVBAR ===== */
|
|
.navbar {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
z-index: 100;
|
|
padding: 16px 0;
|
|
background: rgba(240, 244, 248, 0.75);
|
|
backdrop-filter: blur(20px);
|
|
-webkit-backdrop-filter: blur(20px);
|
|
border-bottom: 1px solid rgba(99, 102, 241, 0.12);
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.navbar.scrolled {
|
|
padding: 12px 0;
|
|
background: rgba(240, 244, 248, 0.97);
|
|
box-shadow: 0 2px 20px rgba(15, 23, 42, 0.08);
|
|
}
|
|
|
|
.nav-inner {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 0 24px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.nav-logo {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.nav-logo-icon {
|
|
width: 38px;
|
|
height: 38px;
|
|
border-radius: 10px;
|
|
background: var(--grad-primary);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 18px;
|
|
color: #fff;
|
|
box-shadow: 0 0 16px rgba(56, 189, 248, 0.4);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.nav-logo-text {
|
|
font-family: "Space Grotesk", sans-serif;
|
|
font-weight: 700;
|
|
font-size: 1.1rem;
|
|
color: var(--clr-text);
|
|
line-height: 1.2;
|
|
}
|
|
|
|
.nav-logo-text span {
|
|
display: block;
|
|
font-size: 0.7rem;
|
|
font-weight: 400;
|
|
color: var(--clr-primary);
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.nav-badge {
|
|
font-size: 0.75rem;
|
|
padding: 5px 14px;
|
|
border-radius: 50px;
|
|
background: rgba(79, 70, 229, 0.08);
|
|
border: 1px solid rgba(79, 70, 229, 0.25);
|
|
color: var(--clr-primary);
|
|
font-weight: 500;
|
|
letter-spacing: 0.02em;
|
|
}
|
|
|
|
/* ===== HERO ===== */
|
|
.hero {
|
|
min-height: 100vh;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
text-align: center;
|
|
padding: 120px 24px 80px;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.hero::before {
|
|
content: "";
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
width: 900px;
|
|
height: 900px;
|
|
background: radial-gradient(
|
|
circle,
|
|
rgba(79, 70, 229, 0.07) 0%,
|
|
rgba(124, 58, 237, 0.04) 40%,
|
|
transparent 70%
|
|
);
|
|
pointer-events: none;
|
|
}
|
|
|
|
.hero-badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
font-size: 0.8rem;
|
|
padding: 7px 18px;
|
|
border-radius: 50px;
|
|
background: rgba(79, 70, 229, 0.08);
|
|
border: 1px solid rgba(79, 70, 229, 0.22);
|
|
color: var(--clr-primary);
|
|
font-weight: 500;
|
|
letter-spacing: 0.06em;
|
|
text-transform: uppercase;
|
|
margin-bottom: 28px;
|
|
animation: fadeSlideDown 0.8s ease both;
|
|
}
|
|
|
|
.hero-badge i {
|
|
font-size: 0.75rem;
|
|
animation: pulse 2s infinite;
|
|
}
|
|
|
|
@keyframes pulse {
|
|
0%,
|
|
100% {
|
|
opacity: 1;
|
|
}
|
|
50% {
|
|
opacity: 0.4;
|
|
}
|
|
}
|
|
|
|
.hero-title {
|
|
font-family: "Space Grotesk", sans-serif;
|
|
font-size: clamp(2.4rem, 6vw, 4.2rem);
|
|
font-weight: 800;
|
|
line-height: 1.1;
|
|
letter-spacing: -0.03em;
|
|
color: var(--clr-text);
|
|
margin-bottom: 20px;
|
|
animation: fadeSlideDown 0.8s 0.1s ease both;
|
|
}
|
|
|
|
.hero-title .gradient-text {
|
|
background: var(--grad-primary);
|
|
-webkit-background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
background-clip: text;
|
|
}
|
|
|
|
.hero-sub {
|
|
font-size: 1.1rem;
|
|
color: var(--clr-muted);
|
|
max-width: 560px;
|
|
margin: 0 auto 40px;
|
|
line-height: 1.7;
|
|
animation: fadeSlideDown 0.8s 0.2s ease both;
|
|
}
|
|
|
|
.hero-stats {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 40px;
|
|
margin-bottom: 56px;
|
|
animation: fadeSlideDown 0.8s 0.3s ease both;
|
|
}
|
|
|
|
.hero-stat {
|
|
text-align: center;
|
|
}
|
|
|
|
.hero-stat-num {
|
|
font-family: "Space Grotesk", sans-serif;
|
|
font-size: 2rem;
|
|
font-weight: 700;
|
|
background: var(--grad-primary);
|
|
-webkit-background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
background-clip: text;
|
|
line-height: 1;
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.hero-stat-label {
|
|
font-size: 0.78rem;
|
|
color: var(--clr-muted);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
}
|
|
|
|
.hero-divider {
|
|
width: 1px;
|
|
height: 40px;
|
|
background: var(--clr-border);
|
|
}
|
|
|
|
.hero-cta {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
padding: 14px 32px;
|
|
border-radius: 50px;
|
|
background: var(--grad-primary);
|
|
color: #fff;
|
|
font-weight: 600;
|
|
font-size: 0.95rem;
|
|
text-decoration: none;
|
|
box-shadow: 0 8px 24px rgba(79, 70, 229, 0.35);
|
|
transition: var(--transition);
|
|
animation: fadeSlideDown 0.8s 0.4s ease both;
|
|
}
|
|
|
|
.hero-cta:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 12px 36px rgba(79, 70, 229, 0.5);
|
|
}
|
|
|
|
/* ===== SCROLL INDICATOR ===== */
|
|
.scroll-indicator {
|
|
position: absolute;
|
|
bottom: 32px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 8px;
|
|
color: var(--clr-muted);
|
|
font-size: 0.75rem;
|
|
letter-spacing: 0.06em;
|
|
text-transform: uppercase;
|
|
animation: fadeSlideDown 0.8s 0.8s ease both;
|
|
}
|
|
|
|
.scroll-indicator .mouse {
|
|
width: 22px;
|
|
height: 34px;
|
|
border: 2px solid rgba(79, 70, 229, 0.3);
|
|
border-radius: 11px;
|
|
display: flex;
|
|
justify-content: center;
|
|
padding-top: 6px;
|
|
}
|
|
|
|
.scroll-indicator .wheel {
|
|
width: 3px;
|
|
height: 6px;
|
|
background: var(--clr-primary);
|
|
border-radius: 2px;
|
|
animation: scrollDown 1.6s infinite;
|
|
}
|
|
|
|
@keyframes scrollDown {
|
|
0% {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
100% {
|
|
opacity: 0;
|
|
transform: translateY(10px);
|
|
}
|
|
}
|
|
|
|
/* ===== SECTION ===== */
|
|
.section {
|
|
padding: 100px 0;
|
|
}
|
|
|
|
.section-label {
|
|
font-size: 0.78rem;
|
|
font-weight: 600;
|
|
letter-spacing: 0.12em;
|
|
text-transform: uppercase;
|
|
color: var(--clr-primary);
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.section-title {
|
|
font-family: "Space Grotesk", sans-serif;
|
|
font-size: clamp(1.8rem, 4vw, 2.6rem);
|
|
font-weight: 700;
|
|
color: var(--clr-text);
|
|
line-height: 1.2;
|
|
letter-spacing: -0.02em;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.section-desc {
|
|
font-size: 1rem;
|
|
color: var(--clr-muted);
|
|
max-width: 520px;
|
|
line-height: 1.7;
|
|
}
|
|
|
|
.section-header {
|
|
display: flex;
|
|
align-items: flex-end;
|
|
justify-content: space-between;
|
|
margin-bottom: 56px;
|
|
gap: 24px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
/* ===== PROJECT CARDS ===== */
|
|
.projects-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
|
|
gap: 28px;
|
|
}
|
|
|
|
.project-card {
|
|
position: relative;
|
|
background: var(--grad-card);
|
|
border: 1px solid var(--clr-border);
|
|
border-radius: var(--radius);
|
|
overflow: hidden;
|
|
text-decoration: none;
|
|
color: var(--clr-text);
|
|
transition: var(--transition);
|
|
display: flex;
|
|
flex-direction: column;
|
|
box-shadow: var(--shadow-card);
|
|
animation: fadeSlideUp 0.6s ease both;
|
|
}
|
|
|
|
.project-card:hover {
|
|
transform: translateY(-6px);
|
|
border-color: rgba(79, 70, 229, 0.35);
|
|
box-shadow:
|
|
0 16px 48px rgba(15, 23, 42, 0.14),
|
|
0 0 0 1px rgba(79, 70, 229, 0.1);
|
|
}
|
|
|
|
.project-card:hover .card-arrow {
|
|
transform: translate(4px, -4px);
|
|
opacity: 1;
|
|
}
|
|
|
|
.project-card:hover .card-icon {
|
|
transform: scale(1.08);
|
|
}
|
|
|
|
.card-header {
|
|
padding: 28px 28px 20px;
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
}
|
|
|
|
.card-icon {
|
|
width: 56px;
|
|
height: 56px;
|
|
border-radius: 14px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 1.4rem;
|
|
transition: var(--transition);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.card-num {
|
|
font-family: "Space Grotesk", sans-serif;
|
|
font-size: 0.75rem;
|
|
font-weight: 600;
|
|
color: var(--clr-muted);
|
|
letter-spacing: 0.08em;
|
|
background: rgba(15, 23, 42, 0.04);
|
|
border: 1px solid rgba(15, 23, 42, 0.1);
|
|
border-radius: 50px;
|
|
padding: 4px 12px;
|
|
}
|
|
|
|
.card-arrow {
|
|
position: absolute;
|
|
top: 24px;
|
|
right: 24px;
|
|
color: var(--clr-primary);
|
|
font-size: 1rem;
|
|
opacity: 0.5;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.card-body {
|
|
padding: 0 28px 28px;
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.card-title {
|
|
font-family: "Space Grotesk", sans-serif;
|
|
font-size: 1.25rem;
|
|
font-weight: 700;
|
|
color: var(--clr-text);
|
|
margin-bottom: 10px;
|
|
letter-spacing: -0.01em;
|
|
line-height: 1.3;
|
|
}
|
|
|
|
.card-desc {
|
|
font-size: 0.88rem;
|
|
color: var(--clr-muted);
|
|
line-height: 1.65;
|
|
margin-bottom: 20px;
|
|
flex: 1;
|
|
}
|
|
|
|
.card-tags {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.tag {
|
|
font-size: 0.72rem;
|
|
font-weight: 500;
|
|
padding: 4px 12px;
|
|
border-radius: 50px;
|
|
letter-spacing: 0.02em;
|
|
}
|
|
|
|
.tag-blue {
|
|
background: #eff6ff;
|
|
color: #1d4ed8;
|
|
border: 1px solid #bfdbfe;
|
|
}
|
|
.tag-purple {
|
|
background: #f5f3ff;
|
|
color: #6d28d9;
|
|
border: 1px solid #ddd6fe;
|
|
}
|
|
.tag-green {
|
|
background: #ecfdf5;
|
|
color: #065f46;
|
|
border: 1px solid #a7f3d0;
|
|
}
|
|
.tag-orange {
|
|
background: #fff7ed;
|
|
color: #9a3412;
|
|
border: 1px solid #fed7aa;
|
|
}
|
|
.tag-pink {
|
|
background: #fdf2f8;
|
|
color: #9d174d;
|
|
border: 1px solid #fbcfe8;
|
|
}
|
|
|
|
.card-footer {
|
|
border-top: 1px solid var(--clr-border);
|
|
padding: 18px 28px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.card-link-btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
font-size: 0.85rem;
|
|
font-weight: 600;
|
|
color: var(--clr-primary);
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.project-card:hover .card-link-btn {
|
|
gap: 12px;
|
|
}
|
|
|
|
.card-status {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-size: 0.75rem;
|
|
}
|
|
|
|
.status-dot {
|
|
width: 7px;
|
|
height: 7px;
|
|
border-radius: 50%;
|
|
animation: statusPulse 2s infinite;
|
|
}
|
|
|
|
.status-dot.active {
|
|
background: var(--clr-accent);
|
|
box-shadow: 0 0 8px var(--clr-accent);
|
|
}
|
|
.status-dot.pending {
|
|
background: var(--clr-warn);
|
|
box-shadow: 0 0 8px var(--clr-warn);
|
|
}
|
|
.status-dot.inactive {
|
|
background: var(--clr-muted);
|
|
}
|
|
|
|
@keyframes statusPulse {
|
|
0%,
|
|
100% {
|
|
opacity: 1;
|
|
}
|
|
50% {
|
|
opacity: 0.4;
|
|
}
|
|
}
|
|
|
|
/* ===== CARD ACCENT LINES ===== */
|
|
.card-glow-line {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 2px;
|
|
border-radius: var(--radius) var(--radius) 0 0;
|
|
}
|
|
|
|
/* ===== COMING SOON CARD ===== */
|
|
.card-overlay {
|
|
position: absolute;
|
|
inset: 0;
|
|
background: rgba(240, 244, 248, 0.75);
|
|
backdrop-filter: blur(3px);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: var(--radius);
|
|
}
|
|
|
|
.coming-soon-badge {
|
|
font-size: 0.8rem;
|
|
font-weight: 600;
|
|
padding: 8px 20px;
|
|
border-radius: 50px;
|
|
background: #fff7ed;
|
|
border: 1px solid #fed7aa;
|
|
color: var(--clr-warn);
|
|
letter-spacing: 0.06em;
|
|
text-transform: uppercase;
|
|
box-shadow: 0 2px 8px rgba(234, 88, 12, 0.15);
|
|
}
|
|
|
|
/* ===== TECH STACK SECTION ===== */
|
|
.tech-strip {
|
|
padding: 60px 0;
|
|
border-top: 1px solid var(--clr-border);
|
|
border-bottom: 1px solid var(--clr-border);
|
|
}
|
|
|
|
.tech-strip-label {
|
|
text-align: center;
|
|
font-size: 0.75rem;
|
|
font-weight: 500;
|
|
letter-spacing: 0.1em;
|
|
text-transform: uppercase;
|
|
color: var(--clr-muted);
|
|
margin-bottom: 32px;
|
|
}
|
|
|
|
.tech-items {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 40px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.tech-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
color: var(--clr-muted);
|
|
font-size: 0.9rem;
|
|
font-weight: 500;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.tech-item:hover {
|
|
color: var(--clr-text);
|
|
}
|
|
|
|
.tech-item i {
|
|
font-size: 1.4rem;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
/* ===== FOOTER ===== */
|
|
.footer {
|
|
padding: 60px 0 40px;
|
|
border-top: 1px solid var(--clr-border);
|
|
}
|
|
|
|
.footer-inner {
|
|
text-align: center;
|
|
}
|
|
|
|
.footer-logo {
|
|
font-family: "Space Grotesk", sans-serif;
|
|
font-size: 1.4rem;
|
|
font-weight: 700;
|
|
color: var(--clr-text);
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.footer-logo span {
|
|
background: var(--grad-primary);
|
|
-webkit-background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
background-clip: text;
|
|
}
|
|
|
|
.footer-course {
|
|
font-size: 0.85rem;
|
|
color: var(--clr-muted);
|
|
margin-bottom: 32px;
|
|
}
|
|
|
|
.footer-divider {
|
|
width: 60px;
|
|
height: 1px;
|
|
background: var(--clr-border);
|
|
margin: 32px auto;
|
|
}
|
|
|
|
.footer-copy {
|
|
font-size: 0.8rem;
|
|
color: var(--clr-muted);
|
|
}
|
|
|
|
.footer-copy a {
|
|
color: var(--clr-primary);
|
|
text-decoration: none;
|
|
}
|
|
|
|
/* ===== ANIMATIONS ===== */
|
|
@keyframes fadeSlideDown {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(-20px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeSlideUp {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(30px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
.reveal {
|
|
opacity: 0;
|
|
transform: translateY(30px);
|
|
transition:
|
|
opacity 0.7s ease,
|
|
transform 0.7s ease;
|
|
}
|
|
|
|
.reveal.visible {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
|
|
/* ===== RESPONSIVE ===== */
|
|
@media (max-width: 640px) {
|
|
.hero-stats {
|
|
gap: 24px;
|
|
}
|
|
.projects-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
.section-header {
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<!-- ===== CANVAS BACKGROUND ===== -->
|
|
<canvas id="bg-canvas"></canvas>
|
|
|
|
<!-- ===== NAVBAR ===== -->
|
|
<nav
|
|
class="navbar"
|
|
id="navbar"
|
|
>
|
|
<div class="nav-inner">
|
|
<a
|
|
href="#"
|
|
class="nav-logo"
|
|
id="logo-link"
|
|
>
|
|
<div class="nav-logo-icon">
|
|
<i class="fa-solid fa-map-location-dot"></i>
|
|
</div>
|
|
<div class="nav-logo-text">
|
|
WebGIS
|
|
<span>Sistem Informasi Geografis</span>
|
|
</div>
|
|
</a>
|
|
<div class="nav-badge">
|
|
<i class="fa-solid fa-graduation-cap"></i> Portofolio Tugas
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- ===== HERO ===== -->
|
|
<section
|
|
class="hero"
|
|
id="home"
|
|
>
|
|
<div class="wrapper">
|
|
<div
|
|
class="hero-badge"
|
|
id="hero-badge"
|
|
>
|
|
<i class="fa-solid fa-circle"></i>
|
|
Sistem Informasi Geografis
|
|
</div>
|
|
|
|
<h1
|
|
class="hero-title"
|
|
id="hero-title"
|
|
>
|
|
Portofolio Proyek<br />
|
|
<span class="gradient-text">WebGIS Interaktif</span>
|
|
</h1>
|
|
|
|
<p
|
|
class="hero-sub"
|
|
id="hero-sub"
|
|
>
|
|
Kumpulan tugas pemetaan berbasis web menggunakan teknologi geospasial
|
|
modern — dari peta jalan, persil, hingga visualisasi data sosial.
|
|
</p>
|
|
|
|
<div id="student-card" style="
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 14px;
|
|
background: rgba(79, 70, 229, 0.07);
|
|
border: 1px solid rgba(79, 70, 229, 0.2);
|
|
border-radius: 14px;
|
|
padding: 12px 22px;
|
|
margin-top: 8px;
|
|
margin-bottom: 4px;
|
|
">
|
|
<div style="width: 42px; height: 42px; border-radius: 50%; background: var(--grad-primary); display: flex; align-items: center; justify-content: center; font-size: 1.2rem;">👤</div>
|
|
<div style="text-align: left;">
|
|
<div style="font-weight: 700; font-size: 0.95rem; color: var(--clr-text);">Syariffullah</div>
|
|
<div style="font-size: 0.78rem; color: var(--clr-muted); font-family: 'Space Grotesk', monospace; letter-spacing: 0.03em;">NIM: D1041231018</div>
|
|
</div>
|
|
<div style="width: 1px; height: 32px; background: rgba(79,70,229,0.2);"></div>
|
|
<div style="font-size: 0.78rem; color: var(--clr-muted); text-align: left;">
|
|
<div><i class="fa-solid fa-graduation-cap" style="color: var(--clr-primary);"></i> Sistem Informasi Geografis</div>
|
|
<div style="margin-top:2px;"><i class="fa-solid fa-microchip" style="color: var(--clr-secondary);"></i> Teknik Informatika</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
class="hero-stats"
|
|
id="hero-stats"
|
|
>
|
|
<div class="hero-stat">
|
|
<div
|
|
class="hero-stat-num"
|
|
id="stat-projects"
|
|
>
|
|
4
|
|
</div>
|
|
<div class="hero-stat-label">Proyek</div>
|
|
</div>
|
|
<div class="hero-divider"></div>
|
|
<div class="hero-stat">
|
|
<div class="hero-stat-num">GIS</div>
|
|
<div class="hero-stat-label">Mata Kuliah</div>
|
|
</div>
|
|
<div class="hero-divider"></div>
|
|
<div class="hero-stat">
|
|
<div class="hero-stat-num">Web</div>
|
|
<div class="hero-stat-label">Platform</div>
|
|
</div>
|
|
</div>
|
|
|
|
<a
|
|
href="#projects"
|
|
class="hero-cta"
|
|
id="hero-cta"
|
|
>
|
|
<i class="fa-solid fa-layer-group"></i>
|
|
Lihat Semua Proyek
|
|
</a>
|
|
|
|
<div class="scroll-indicator">
|
|
<div class="mouse"><div class="wheel"></div></div>
|
|
<span>Scroll</span>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- ===== TECH STRIP ===== -->
|
|
<div class="tech-strip">
|
|
<div class="wrapper">
|
|
<p class="tech-strip-label">Teknologi yang Digunakan</p>
|
|
<div class="tech-items">
|
|
<div class="tech-item">
|
|
<i
|
|
class="fa-solid fa-map"
|
|
style="color: #4f46e5"
|
|
></i>
|
|
Leaflet.js
|
|
</div>
|
|
<div class="tech-item">
|
|
<i
|
|
class="fa-brands fa-php"
|
|
style="color: #7c3aed"
|
|
></i>
|
|
PHP
|
|
</div>
|
|
<div class="tech-item">
|
|
<i
|
|
class="fa-solid fa-database"
|
|
style="color: #059669"
|
|
></i>
|
|
MySQL
|
|
</div>
|
|
<div class="tech-item">
|
|
<i
|
|
class="fa-brands fa-html5"
|
|
style="color: #ea580c"
|
|
></i>
|
|
HTML / CSS / JS
|
|
</div>
|
|
<div class="tech-item">
|
|
<i
|
|
class="fa-solid fa-globe"
|
|
style="color: #db2777"
|
|
></i>
|
|
GeoJSON
|
|
</div>
|
|
<div class="tech-item">
|
|
<i
|
|
class="fa-solid fa-server"
|
|
style="color: #b45309"
|
|
></i>
|
|
XAMPP
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ===== PROJECTS ===== -->
|
|
<section
|
|
class="section"
|
|
id="projects"
|
|
>
|
|
<div class="wrapper">
|
|
<div class="section-header reveal">
|
|
<div>
|
|
<p class="section-label">
|
|
<i class="fa-solid fa-folder-open"></i> Daftar Proyek
|
|
</p>
|
|
<h2 class="section-title">Semua Tugas WebGIS</h2>
|
|
<p class="section-desc">
|
|
Klik pada kartu proyek untuk membuka aplikasi pemetaan interaktif.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="projects-grid">
|
|
<!-- ===== PROJECT 1: POVERTY ===== -->
|
|
<a
|
|
href="/webgis/poverty/index.php"
|
|
class="project-card"
|
|
id="card-poverty"
|
|
style="animation-delay: 0.05s"
|
|
>
|
|
<div
|
|
class="card-glow-line"
|
|
style="background: linear-gradient(90deg, #38bdf8, #818cf8)"
|
|
></div>
|
|
<div class="card-arrow">
|
|
<i class="fa-solid fa-arrow-up-right"></i>
|
|
</div>
|
|
<div class="card-header">
|
|
<div
|
|
class="card-icon"
|
|
style="
|
|
background: rgba(56, 189, 248, 0.12);
|
|
border: 1px solid rgba(56, 189, 248, 0.2);
|
|
"
|
|
>
|
|
🏠
|
|
</div>
|
|
<span class="card-num">01</span>
|
|
</div>
|
|
<div class="card-body">
|
|
<h3 class="card-title">
|
|
Pemetaan Kemiskinan<br />Kota Pontianak
|
|
</h3>
|
|
<p class="card-desc">
|
|
Aplikasi WebGIS untuk memetakan sebaran penduduk miskin, rumah
|
|
ibadah, dan log bantuan sosial di Kota Pontianak. Dilengkapi
|
|
manajemen data spasial berbasis peran.
|
|
</p>
|
|
<div class="card-tags">
|
|
<span class="tag tag-blue">Leaflet.js</span>
|
|
<span class="tag tag-purple">PHP</span>
|
|
<span class="tag tag-green">MySQL Spatial</span>
|
|
<span class="tag tag-orange">GeoJSON</span>
|
|
<span class="tag tag-pink">Role-based</span>
|
|
</div>
|
|
</div>
|
|
<div class="card-footer">
|
|
<span class="card-link-btn">
|
|
Buka Proyek <i class="fa-solid fa-arrow-right"></i>
|
|
</span>
|
|
<div class="card-status">
|
|
<div class="status-dot active"></div>
|
|
<span style="color: var(--clr-muted); font-size: 0.75rem"
|
|
>Aktif</span
|
|
>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
|
|
<!-- ===== PROJECT 2: JALAN ===== -->
|
|
<a
|
|
href="/webgis/jalan/index.php"
|
|
class="project-card"
|
|
id="card-jalan"
|
|
style="animation-delay: 0.1s"
|
|
>
|
|
<div
|
|
class="card-glow-line"
|
|
style="background: linear-gradient(90deg, #818cf8, #f472b6)"
|
|
></div>
|
|
<div class="card-arrow">
|
|
<i class="fa-solid fa-arrow-up-right"></i>
|
|
</div>
|
|
<div class="card-header">
|
|
<div
|
|
class="card-icon"
|
|
style="
|
|
background: rgba(129, 140, 248, 0.12);
|
|
border: 1px solid rgba(129, 140, 248, 0.2);
|
|
"
|
|
>
|
|
🛣️
|
|
</div>
|
|
<span class="card-num">02</span>
|
|
</div>
|
|
<div class="card-body">
|
|
<h3 class="card-title">Pemetaan Jaringan<br />Jalan</h3>
|
|
<p class="card-desc">
|
|
Visualisasi dan analisis jaringan jalan menggunakan data
|
|
spasial. Mencakup klasifikasi jalan, kondisi, dan data atribut
|
|
terkait infrastruktur jalan.
|
|
</p>
|
|
<div class="card-tags">
|
|
<span class="tag tag-purple">WebGIS</span>
|
|
<span class="tag tag-blue">Shapefile</span>
|
|
<span class="tag tag-green">Road Network</span>
|
|
</div>
|
|
</div>
|
|
<div class="card-footer">
|
|
<span class="card-link-btn">
|
|
Buka Proyek <i class="fa-solid fa-arrow-right"></i>
|
|
</span>
|
|
<div class="card-status">
|
|
<div class="status-dot active"></div>
|
|
<span style="color: var(--clr-muted); font-size: 0.75rem"
|
|
>Aktif</span
|
|
>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
|
|
<!-- ===== PROJECT 3: PARSIL ===== -->
|
|
<a
|
|
href="/webgis/parsil/index.php"
|
|
class="project-card"
|
|
id="card-parsil"
|
|
style="animation-delay: 0.15s"
|
|
>
|
|
<div
|
|
class="card-glow-line"
|
|
style="background: linear-gradient(90deg, #34d399, #38bdf8)"
|
|
></div>
|
|
<div class="card-arrow">
|
|
<i class="fa-solid fa-arrow-up-right"></i>
|
|
</div>
|
|
<div class="card-header">
|
|
<div
|
|
class="card-icon"
|
|
style="
|
|
background: rgba(52, 211, 153, 0.12);
|
|
border: 1px solid rgba(52, 211, 153, 0.2);
|
|
"
|
|
>
|
|
🗺️
|
|
</div>
|
|
<span class="card-num">03</span>
|
|
</div>
|
|
<div class="card-body">
|
|
<h3 class="card-title">Pemetaan Bidang<br />Tanah (Parsil)</h3>
|
|
<p class="card-desc">
|
|
Sistem informasi geografis untuk pemetaan bidang tanah,
|
|
kepemilikan lahan, dan informasi pertanahan berbasis web yang
|
|
terintegrasi dengan data spasial.
|
|
</p>
|
|
<div class="card-tags">
|
|
<span class="tag tag-green">Land Parcel</span>
|
|
<span class="tag tag-blue">Polygon</span>
|
|
<span class="tag tag-orange">Cadastral</span>
|
|
</div>
|
|
</div>
|
|
<div class="card-footer">
|
|
<span class="card-link-btn">
|
|
Buka Proyek <i class="fa-solid fa-arrow-right"></i>
|
|
</span>
|
|
<div class="card-status">
|
|
<div class="status-dot active"></div>
|
|
<span style="color: var(--clr-muted); font-size: 0.75rem"
|
|
>Aktif</span
|
|
>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
|
|
<!-- ===== PROJECT 4: SPBU ===== -->
|
|
<a
|
|
href="/webgis/spbu/index.php"
|
|
class="project-card"
|
|
id="card-spbu"
|
|
style="animation-delay: 0.2s"
|
|
>
|
|
<div
|
|
class="card-glow-line"
|
|
style="background: linear-gradient(90deg, #fb923c, #facc15)"
|
|
></div>
|
|
<div class="card-arrow">
|
|
<i class="fa-solid fa-arrow-up-right"></i>
|
|
</div>
|
|
<div class="card-header">
|
|
<div
|
|
class="card-icon"
|
|
style="
|
|
background: rgba(251, 146, 60, 0.12);
|
|
border: 1px solid rgba(251, 146, 60, 0.2);
|
|
"
|
|
>
|
|
⛽
|
|
</div>
|
|
<span class="card-num">04</span>
|
|
</div>
|
|
<div class="card-body">
|
|
<h3 class="card-title">Pemetaan Lokasi<br />SPBU</h3>
|
|
<p class="card-desc">
|
|
Peta interaktif untuk menampilkan sebaran Stasiun Pengisian
|
|
Bahan Bakar Umum (SPBU) beserta informasi detail, analisis
|
|
jangkauan, dan fasilitas yang tersedia.
|
|
</p>
|
|
<div class="card-tags">
|
|
<span class="tag tag-orange">POI Mapping</span>
|
|
<span class="tag tag-blue">Leaflet.js</span>
|
|
<span class="tag tag-pink">Radius Analysis</span>
|
|
</div>
|
|
</div>
|
|
<div class="card-footer">
|
|
<span class="card-link-btn">
|
|
Buka Proyek <i class="fa-solid fa-arrow-right"></i>
|
|
</span>
|
|
<div class="card-status">
|
|
<div class="status-dot active"></div>
|
|
<span style="color: var(--clr-muted); font-size: 0.75rem"
|
|
>Aktif</span
|
|
>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- ===== FOOTER ===== -->
|
|
<footer class="footer">
|
|
<div class="wrapper">
|
|
<div class="footer-inner">
|
|
<div class="footer-logo">Web<span>GIS</span></div>
|
|
<div class="footer-course">
|
|
Mata Kuliah Sistem Informasi Geografis · Portofolio
|
|
Tugas Mahasiswa
|
|
</div>
|
|
<div
|
|
style="
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 16px;
|
|
flex-wrap: wrap;
|
|
"
|
|
>
|
|
<span style="font-size: 0.8rem; color: var(--clr-muted)">
|
|
<i
|
|
class="fa-solid fa-map-location-dot"
|
|
style="color: var(--clr-primary)"
|
|
></i>
|
|
Leaflet.js
|
|
</span>
|
|
<span style="color: var(--clr-border)">|</span>
|
|
<span style="font-size: 0.8rem; color: var(--clr-muted)">
|
|
<i
|
|
class="fa-solid fa-database"
|
|
style="color: var(--clr-accent)"
|
|
></i>
|
|
MySQL Spatial
|
|
</span>
|
|
<span style="color: var(--clr-border)">|</span>
|
|
<span style="font-size: 0.8rem; color: var(--clr-muted)">
|
|
<i
|
|
class="fa-brands fa-php"
|
|
style="color: var(--clr-secondary)"
|
|
></i>
|
|
PHP / XAMPP
|
|
</span>
|
|
</div>
|
|
<div class="footer-divider"></div>
|
|
<p style="font-size: 0.9rem; color: var(--clr-text); font-weight: 600; margin-bottom: 6px;">
|
|
Syariffullah <span style="font-family: 'Space Grotesk', monospace; color: var(--clr-primary); font-size: 0.82rem; background: rgba(79,70,229,0.08); padding: 2px 8px; border-radius: 6px;">D1041231018</span>
|
|
</p>
|
|
<p class="footer-copy">
|
|
© 2025 WebGIS Portfolio · Sistem Informasi Geografis
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
<!-- ===== SCRIPTS ===== -->
|
|
<script>
|
|
/* ----- CANVAS PARTICLE / GRID BG ----- */
|
|
(function () {
|
|
const canvas = document.getElementById("bg-canvas");
|
|
const ctx = canvas.getContext("2d");
|
|
let w, h, animId;
|
|
const DOTS = [];
|
|
const LINES = [];
|
|
const COUNT = 60;
|
|
|
|
function resize() {
|
|
w = canvas.width = window.innerWidth;
|
|
h = canvas.height = window.innerHeight;
|
|
}
|
|
resize();
|
|
window.addEventListener("resize", resize);
|
|
|
|
// Grid lines
|
|
function drawGrid() {
|
|
ctx.strokeStyle = "rgba(79,70,229,0.06)";
|
|
ctx.lineWidth = 1;
|
|
const step = 60;
|
|
for (let x = 0; x < w; x += step) {
|
|
ctx.beginPath();
|
|
ctx.moveTo(x, 0);
|
|
ctx.lineTo(x, h);
|
|
ctx.stroke();
|
|
}
|
|
for (let y = 0; y < h; y += step) {
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, y);
|
|
ctx.lineTo(w, y);
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
|
|
// Particles
|
|
for (let i = 0; i < COUNT; i++) {
|
|
DOTS.push({
|
|
x: Math.random() * window.innerWidth,
|
|
y: Math.random() * window.innerHeight,
|
|
vx: (Math.random() - 0.5) * 0.3,
|
|
vy: (Math.random() - 0.5) * 0.3,
|
|
r: Math.random() * 2 + 0.5,
|
|
a: Math.random(),
|
|
});
|
|
}
|
|
|
|
function draw() {
|
|
ctx.clearRect(0, 0, w, h);
|
|
drawGrid();
|
|
|
|
// Move and draw dots
|
|
DOTS.forEach((d) => {
|
|
d.x += d.vx;
|
|
d.y += d.vy;
|
|
if (d.x < 0) d.x = w;
|
|
if (d.x > w) d.x = 0;
|
|
if (d.y < 0) d.y = h;
|
|
if (d.y > h) d.y = 0;
|
|
|
|
ctx.beginPath();
|
|
ctx.arc(d.x, d.y, d.r, 0, Math.PI * 2);
|
|
ctx.fillStyle = `rgba(79,70,229,${d.a * 0.4})`;
|
|
ctx.fill();
|
|
});
|
|
|
|
// Connect nearby dots
|
|
for (let i = 0; i < DOTS.length; i++) {
|
|
for (let j = i + 1; j < DOTS.length; j++) {
|
|
const dx = DOTS[i].x - DOTS[j].x;
|
|
const dy = DOTS[i].y - DOTS[j].y;
|
|
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
if (dist < 120) {
|
|
ctx.beginPath();
|
|
ctx.moveTo(DOTS[i].x, DOTS[i].y);
|
|
ctx.lineTo(DOTS[j].x, DOTS[j].y);
|
|
ctx.strokeStyle = `rgba(79,70,229,${0.12 * (1 - dist / 120)})`;
|
|
ctx.lineWidth = 0.8;
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
}
|
|
|
|
animId = requestAnimationFrame(draw);
|
|
}
|
|
draw();
|
|
})();
|
|
|
|
/* ----- NAVBAR SCROLL ----- */
|
|
const navbar = document.getElementById("navbar");
|
|
window.addEventListener("scroll", () => {
|
|
navbar.classList.toggle("scrolled", window.scrollY > 40);
|
|
});
|
|
|
|
/* ----- SCROLL REVEAL ----- */
|
|
const revealEls = document.querySelectorAll(".reveal");
|
|
const revealObs = new IntersectionObserver(
|
|
(entries) => {
|
|
entries.forEach((e) => {
|
|
if (e.isIntersecting) {
|
|
e.target.classList.add("visible");
|
|
revealObs.unobserve(e.target);
|
|
}
|
|
});
|
|
},
|
|
{ threshold: 0.15 },
|
|
);
|
|
revealEls.forEach((el) => revealObs.observe(el));
|
|
|
|
/* ----- CARD REVEAL ----- */
|
|
const cardEls = document.querySelectorAll(".project-card");
|
|
const cardObs = new IntersectionObserver(
|
|
(entries) => {
|
|
entries.forEach((e) => {
|
|
if (e.isIntersecting) {
|
|
e.target.style.opacity = "1";
|
|
e.target.style.transform = "translateY(0)";
|
|
cardObs.unobserve(e.target);
|
|
}
|
|
});
|
|
},
|
|
{ threshold: 0.1 },
|
|
);
|
|
cardEls.forEach((card) => {
|
|
card.style.opacity = "0";
|
|
card.style.transform = "translateY(30px)";
|
|
card.style.transition = "opacity 0.6s ease, transform 0.6s ease";
|
|
cardObs.observe(card);
|
|
});
|
|
|
|
/* ----- SMOOTH HERO CTA ----- */
|
|
document.getElementById("hero-cta").addEventListener("click", (e) => {
|
|
e.preventDefault();
|
|
document
|
|
.getElementById("projects")
|
|
.scrollIntoView({ behavior: "smooth" });
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|