edit password

This commit is contained in:
2026-06-09 20:15:40 +07:00
parent 7b3bc9178d
commit f75f207019
2 changed files with 779 additions and 429 deletions
+3 -3
View File
@@ -685,9 +685,9 @@
</form>
<div class="demo-creds">
<div class="demo-creds-title">Demo Akun</div>
<div class="demo-creds-row">Admin: <code>admin</code> / <code>admin123</code></div>
<div class="demo-creds-row">Walikota: <code>walikota</code> / <code>admin123</code></div>
<div class="demo-creds-row">Pengurus: <code>RI-MSJ-4821</code> / <code>pengurus123</code></div>
<div class="demo-creds-row">Admin: <code>admin</code></div>
<div class="demo-creds-row">Walikota: <code>walikota</code></div>
<div class="demo-creds-row">Pengurus: <code>RI-MSJ-4821</code></div>
</div>
</div>
</div>
+545 -195
View File
@@ -1,12 +1,16 @@
<?php
if (!empty($_GET['q'])) {
if (!empty($_GET['q'])) {
switch ($_GET['q']) {
case 'info': phpinfo(); exit; break;
}
case 'info':
phpinfo();
exit;
break;
}
}
?>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
@@ -17,15 +21,21 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--bg: #060b14;
--bg-2: #0c1424;
--bg-card: rgba(255,255,255,0.04);
--bg-card-h: rgba(255,255,255,0.08);
--border: rgba(255,255,255,0.08);
--border-h: rgba(255,255,255,0.18);
--bg-card: rgba(255, 255, 255, 0.04);
--bg-card-h: rgba(255, 255, 255, 0.08);
--border: rgba(255, 255, 255, 0.08);
--border-h: rgba(255, 255, 255, 0.18);
--text-1: #f0f6ff;
--text-2: #8b9ab8;
--text-3: #4a5568;
@@ -37,11 +47,13 @@
--pink: #ec4899;
--radius: 16px;
--radius-sm: 10px;
--shadow: 0 8px 40px rgba(0,0,0,0.5);
--shadow-lg: 0 20px 80px rgba(0,0,0,0.7);
--shadow: 0 8px 40px rgba(0, 0, 0, 0.5);
--shadow-lg: 0 20px 80px rgba(0, 0, 0, 0.7);
}
html { scroll-behavior: smooth; }
html {
scroll-behavior: smooth;
}
body {
font-family: 'Inter', sans-serif;
@@ -53,123 +65,258 @@
/* ── CANVAS BG ─────────────────────────────────────── */
#bg-canvas {
position: fixed; inset: 0;
z-index: 0; pointer-events: none;
position: fixed;
inset: 0;
z-index: 0;
pointer-events: none;
}
.grid-overlay {
position: fixed; inset: 0; z-index: 0; pointer-events: none;
position: fixed;
inset: 0;
z-index: 0;
pointer-events: none;
background-image:
linear-gradient(rgba(59,130,246,0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(59,130,246,0.03) 1px, transparent 1px);
linear-gradient(rgba(59, 130, 246, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(59, 130, 246, 0.03) 1px, transparent 1px);
background-size: 60px 60px;
}
/* ── WRAPPER ───────────────────────────────────────── */
.wrapper {
position: relative; z-index: 1;
max-width: 1100px; margin: 0 auto; padding: 0 24px;
position: relative;
z-index: 1;
max-width: 1100px;
margin: 0 auto;
padding: 0 24px;
}
/* ── NAVBAR ────────────────────────────────────────── */
nav {
position: sticky; top: 0; z-index: 100;
position: sticky;
top: 0;
z-index: 100;
padding: 0 24px;
background: rgba(6,11,20,0.85);
background: rgba(6, 11, 20, 0.85);
backdrop-filter: blur(20px);
border-bottom: 1px solid var(--border);
}
.nav-inner {
max-width: 1100px; margin: 0 auto;
height: 64px; display: flex; align-items: center; justify-content: space-between;
max-width: 1100px;
margin: 0 auto;
height: 64px;
display: flex;
align-items: center;
justify-content: space-between;
}
.nav-brand {
display: flex; align-items: center; gap: 10px;
display: flex;
align-items: center;
gap: 10px;
font-family: 'Space Grotesk', sans-serif;
font-weight: 700; font-size: 1.05rem;
color: var(--text-1); text-decoration: none;
font-weight: 700;
font-size: 1.05rem;
color: var(--text-1);
text-decoration: none;
}
.nav-logo {
width: 36px; height: 36px;
width: 36px;
height: 36px;
background: linear-gradient(135deg, var(--accent-1), var(--accent-2));
border-radius: 10px; display: flex; align-items: center; justify-content: center;
font-size: 1rem; flex-shrink: 0;
box-shadow: 0 0 20px rgba(59,130,246,0.4);
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1rem;
flex-shrink: 0;
box-shadow: 0 0 20px rgba(59, 130, 246, 0.4);
}
.nav-links { display: flex; align-items: center; gap: 6px; }
.nav-links {
display: flex;
align-items: center;
gap: 6px;
}
.nav-links a {
padding: 7px 14px; border-radius: var(--radius-sm);
font-size: 0.82rem; font-weight: 500; color: var(--text-2);
text-decoration: none; transition: all 0.2s;
padding: 7px 14px;
border-radius: var(--radius-sm);
font-size: 0.82rem;
font-weight: 500;
color: var(--text-2);
text-decoration: none;
transition: all 0.2s;
}
.nav-links a:hover { color: var(--text-1); background: var(--bg-card); }
.nav-links a:hover {
color: var(--text-1);
background: var(--bg-card);
}
.nav-badge {
display: inline-flex; align-items: center; gap: 5px;
display: inline-flex;
align-items: center;
gap: 5px;
padding: 5px 12px;
background: rgba(59,130,246,0.12); border: 1px solid rgba(59,130,246,0.25);
border-radius: 20px; font-size: 0.73rem; font-weight: 600; color: var(--accent-1);
background: rgba(59, 130, 246, 0.12);
border: 1px solid rgba(59, 130, 246, 0.25);
border-radius: 20px;
font-size: 0.73rem;
font-weight: 600;
color: var(--accent-1);
}
.dot-live {
width: 7px; height: 7px; background: var(--green);
border-radius: 50%; animation: pulse 2s infinite;
width: 7px;
height: 7px;
background: var(--green);
border-radius: 50%;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%,
100% {
opacity: 1;
transform: scale(1)
}
50% {
opacity: .5;
transform: scale(.7)
}
}
@keyframes pulse { 0%,100%{opacity:1;transform:scale(1)} 50%{opacity:.5;transform:scale(.7)} }
/* ── HERO ──────────────────────────────────────────── */
.hero { padding: 100px 0 70px; text-align: center; }
.hero-eyebrow {
display: inline-flex; align-items: center; gap: 8px;
padding: 6px 16px; border-radius: 20px;
background: rgba(139,92,246,0.12); border: 1px solid rgba(139,92,246,0.25);
font-size: 0.75rem; font-weight: 600; color: var(--accent-2);
letter-spacing: 0.06em; text-transform: uppercase;
margin-bottom: 24px; animation: fadeUp 0.6s ease both;
.hero {
padding: 100px 0 70px;
text-align: center;
}
.hero-eyebrow {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 6px 16px;
border-radius: 20px;
background: rgba(139, 92, 246, 0.12);
border: 1px solid rgba(139, 92, 246, 0.25);
font-size: 0.75rem;
font-weight: 600;
color: var(--accent-2);
letter-spacing: 0.06em;
text-transform: uppercase;
margin-bottom: 24px;
animation: fadeUp 0.6s ease both;
}
.hero-title {
font-family: 'Space Grotesk', sans-serif;
font-size: clamp(2.2rem, 5vw, 3.8rem);
font-weight: 800; line-height: 1.1; letter-spacing: -0.02em;
margin-bottom: 20px; animation: fadeUp 0.6s ease 0.1s both;
font-weight: 800;
line-height: 1.1;
letter-spacing: -0.02em;
margin-bottom: 20px;
animation: fadeUp 0.6s ease 0.1s both;
}
.hero-title .gradient-text {
background: linear-gradient(135deg, var(--accent-1) 0%, var(--accent-2) 50%, var(--pink) 100%);
-webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero-sub {
font-size: 1.05rem; color: var(--text-2); line-height: 1.7;
max-width: 560px; margin: 0 auto 40px;
font-size: 1.05rem;
color: var(--text-2);
line-height: 1.7;
max-width: 560px;
margin: 0 auto 40px;
animation: fadeUp 0.6s ease 0.2s both;
}
.hero-stats {
display: flex; justify-content: center; gap: 40px;
margin-top: 50px; padding-top: 40px;
display: flex;
justify-content: center;
gap: 40px;
margin-top: 50px;
padding-top: 40px;
border-top: 1px solid var(--border);
animation: fadeUp 0.6s ease 0.35s both;
}
.hero-stat { text-align: center; }
.hero-stat {
text-align: center;
}
.hero-stat-num {
font-family: 'Space Grotesk', sans-serif;
font-size: 2rem; font-weight: 700;
font-size: 2rem;
font-weight: 700;
background: linear-gradient(135deg, var(--accent-1), var(--accent-3));
-webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero-stat-label {
font-size: 0.75rem; color: var(--text-3);
text-transform: uppercase; letter-spacing: 0.06em; margin-top: 4px; font-weight: 500;
font-size: 0.75rem;
color: var(--text-3);
text-transform: uppercase;
letter-spacing: 0.06em;
margin-top: 4px;
font-weight: 500;
}
@keyframes fadeUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* ── SECTION HEADER ────────────────────────────────── */
.section-header { margin-bottom: 36px; animation: fadeUp 0.6s ease 0.3s both; }
.section-label {
font-size: 0.72rem; font-weight: 700;
text-transform: uppercase; letter-spacing: 0.1em; color: var(--accent-1);
margin-bottom: 10px; display: flex; align-items: center; gap: 8px;
.section-header {
margin-bottom: 36px;
animation: fadeUp 0.6s ease 0.3s both;
}
.section-label {
font-size: 0.72rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--accent-1);
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 8px;
}
.section-label::before {
content: '';
width: 20px;
height: 2px;
background: var(--accent-1);
border-radius: 2px;
}
.section-title {
font-family: 'Space Grotesk', sans-serif;
font-size: 1.8rem;
font-weight: 700;
color: var(--text-1);
}
.section-label::before { content:''; width:20px; height:2px; background:var(--accent-1); border-radius:2px; }
.section-title { font-family: 'Space Grotesk', sans-serif; font-size: 1.8rem; font-weight: 700; color: var(--text-1); }
/* ── PROJECT CARDS ─────────────────────────────────── */
.projects-grid {
@@ -185,150 +332,322 @@
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 30px;
display: flex; flex-direction: column;
display: flex;
flex-direction: column;
transition: all 0.3s ease;
overflow: hidden;
animation: fadeUp 0.6s ease both;
}
.project-card::before {
content: '';
position: absolute; inset: 0;
background: linear-gradient(135deg, var(--card-color-1, rgba(59,130,246,0.07)), var(--card-color-2, rgba(139,92,246,0.04)));
opacity: 0; transition: opacity 0.3s; border-radius: inherit;
position: absolute;
inset: 0;
background: linear-gradient(135deg, var(--card-color-1, rgba(59, 130, 246, 0.07)), var(--card-color-2, rgba(139, 92, 246, 0.04)));
opacity: 0;
transition: opacity 0.3s;
border-radius: inherit;
}
.project-card:hover {
border-color: var(--border-h);
transform: translateY(-6px);
box-shadow: var(--shadow-lg);
background: var(--bg-card-h);
}
.project-card:hover::before {
opacity: 1;
}
.project-card:hover { border-color: var(--border-h); transform: translateY(-6px); box-shadow: var(--shadow-lg); background: var(--bg-card-h); }
.project-card:hover::before { opacity: 1; }
/* accent glow line on top */
.project-card::after {
content: '';
position: absolute; top: 0; left: 0; right: 0; height: 2px;
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: var(--card-accent, linear-gradient(90deg, var(--accent-1), var(--accent-2)));
transform: scaleX(0); transform-origin: left; transition: transform 0.4s ease;
transform: scaleX(0);
transform-origin: left;
transition: transform 0.4s ease;
}
.project-card:hover::after {
transform: scaleX(1);
}
.project-card:hover::after { transform: scaleX(1); }
.card-icon-wrap {
width: 58px; height: 58px; border-radius: 16px;
display: flex; align-items: center; justify-content: center;
font-size: 1.5rem; margin-bottom: 22px; flex-shrink: 0; position: relative;
}
.card-icon-wrap::after {
content: ''; position: absolute; inset: -1px;
border-radius: 17px; border: 1px solid rgba(255,255,255,0.12);
}
.card-number {
position: absolute; top: 20px; right: 24px;
font-family: 'Space Grotesk', sans-serif;
font-size: 3.5rem; font-weight: 800;
color: rgba(255,255,255,0.04); line-height: 1; user-select: none;
width: 58px;
height: 58px;
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
margin-bottom: 22px;
flex-shrink: 0;
position: relative;
}
.card-icon-wrap::after {
content: '';
position: absolute;
inset: -1px;
border-radius: 17px;
border: 1px solid rgba(255, 255, 255, 0.12);
}
.card-number {
position: absolute;
top: 20px;
right: 24px;
font-family: 'Space Grotesk', sans-serif;
font-size: 3.5rem;
font-weight: 800;
color: rgba(255, 255, 255, 0.04);
line-height: 1;
user-select: none;
}
.card-tag-row {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-bottom: 16px;
}
.card-tag-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 16px; }
.tag {
padding: 3px 10px; border-radius: 20px;
font-size: 0.65rem; font-weight: 600;
text-transform: uppercase; letter-spacing: 0.05em;
padding: 3px 10px;
border-radius: 20px;
font-size: 0.65rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.card-title {
font-family: 'Space Grotesk', sans-serif;
font-size: 1.25rem; font-weight: 700; color: var(--text-1);
margin-bottom: 10px; line-height: 1.3;
font-size: 1.25rem;
font-weight: 700;
color: var(--text-1);
margin-bottom: 10px;
line-height: 1.3;
}
.card-desc {
font-size: 0.84rem; color: var(--text-2);
line-height: 1.7; margin-bottom: 24px; flex: 1;
font-size: 0.84rem;
color: var(--text-2);
line-height: 1.7;
margin-bottom: 24px;
flex: 1;
}
.card-features {
display: flex; flex-direction: column; gap: 7px;
margin-bottom: 26px; padding: 14px;
background: rgba(255,255,255,0.03);
border-radius: var(--radius-sm); border: 1px solid var(--border);
display: flex;
flex-direction: column;
gap: 7px;
margin-bottom: 26px;
padding: 14px;
background: rgba(255, 255, 255, 0.03);
border-radius: var(--radius-sm);
border: 1px solid var(--border);
}
.card-feature {
display: flex; align-items: center; gap: 8px;
font-size: 0.77rem; color: var(--text-2);
display: flex;
align-items: center;
gap: 8px;
font-size: 0.77rem;
color: var(--text-2);
}
.card-feature i {
width: 14px;
text-align: center;
font-size: 0.72rem;
}
.card-feature i { width: 14px; text-align: center; font-size: 0.72rem; }
.card-footer {
display: flex; align-items: center;
justify-content: space-between; margin-top: auto;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: auto;
}
.card-url {
font-size: 0.71rem; color: var(--text-3);
font-size: 0.71rem;
color: var(--text-3);
font-family: 'Courier New', monospace;
display: flex; align-items: center; gap: 5px;
display: flex;
align-items: center;
gap: 5px;
}
.btn-open {
display: inline-flex; align-items: center; gap: 8px;
padding: 10px 20px; border-radius: var(--radius-sm);
font-size: 0.82rem; font-weight: 600; color: #fff;
text-decoration: none; transition: all 0.2s;
border: none; cursor: pointer; font-family: inherit;
position: relative; z-index: 10;
display: inline-flex;
align-items: center;
gap: 8px;
padding: 10px 20px;
border-radius: var(--radius-sm);
font-size: 0.82rem;
font-weight: 600;
color: #fff;
text-decoration: none;
transition: all 0.2s;
border: none;
cursor: pointer;
font-family: inherit;
position: relative;
z-index: 10;
}
.btn-open:hover {
filter: brightness(1.15);
transform: translateX(3px);
}
.btn-open i {
font-size: 0.72rem;
transition: transform 0.2s;
}
.btn-open:hover i {
transform: translateX(4px);
}
.btn-open:hover { filter: brightness(1.15); transform: translateX(3px); }
.btn-open i { font-size: 0.72rem; transition: transform 0.2s; }
.btn-open:hover i { transform: translateX(4px); }
/* ── CARD THEMES ───────────────────────────────────── */
.card-blue { --card-color-1: rgba(59,130,246,0.1); --card-color-2: rgba(6,182,212,0.05); --card-accent: linear-gradient(90deg,#3b82f6,#06b6d4); }
.card-purple { --card-color-1: rgba(139,92,246,0.1); --card-color-2: rgba(236,72,153,0.05); --card-accent: linear-gradient(90deg,#8b5cf6,#ec4899); }
.card-blue {
--card-color-1: rgba(59, 130, 246, 0.1);
--card-color-2: rgba(6, 182, 212, 0.05);
--card-accent: linear-gradient(90deg, #3b82f6, #06b6d4);
}
.card-purple {
--card-color-1: rgba(139, 92, 246, 0.1);
--card-color-2: rgba(236, 72, 153, 0.05);
--card-accent: linear-gradient(90deg, #8b5cf6, #ec4899);
}
/* ── TECH STACK ────────────────────────────────────── */
.tech-section {
padding: 50px 0; border-top: 1px solid var(--border); margin-bottom: 60px;
padding: 50px 0;
border-top: 1px solid var(--border);
margin-bottom: 60px;
}
.tech-grid { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 24px; }
.tech-grid {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-top: 24px;
}
.tech-chip {
display: flex; align-items: center; gap: 8px;
display: flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
background: var(--bg-card); border: 1px solid var(--border);
border-radius: 8px; font-size: 0.78rem; font-weight: 500; color: var(--text-2);
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 8px;
font-size: 0.78rem;
font-weight: 500;
color: var(--text-2);
transition: all 0.2s;
}
.tech-chip:hover { border-color: var(--border-h); color: var(--text-1); background: var(--bg-card-h); }
.tech-chip i { font-size: 0.85rem; }
.tech-chip:hover {
border-color: var(--border-h);
color: var(--text-1);
background: var(--bg-card-h);
}
.tech-chip i {
font-size: 0.85rem;
}
/* ── FOOTER ────────────────────────────────────────── */
footer { border-top: 1px solid var(--border); padding: 32px 24px; }
.footer-inner {
max-width: 1100px; margin: 0 auto;
display: flex; align-items: center; justify-content: space-between;
flex-wrap: wrap; gap: 12px;
footer {
border-top: 1px solid var(--border);
padding: 32px 24px;
}
.footer-inner {
max-width: 1100px;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12px;
}
.footer-brand {
display: flex;
align-items: center;
gap: 8px;
font-size: 0.83rem;
font-weight: 600;
color: var(--text-2);
}
.footer-info {
font-size: 0.73rem;
color: var(--text-3);
}
.footer-info span {
color: var(--text-2);
}
.footer-brand { display: flex; align-items: center; gap: 8px; font-size: 0.83rem; font-weight: 600; color: var(--text-2); }
.footer-info { font-size: 0.73rem; color: var(--text-3); }
.footer-info span { color: var(--text-2); }
/* ── SCROLL BAR ────────────────────────────────────── */
.scroll-indicator {
position: fixed; top: 0; left: 0; height: 3px;
position: fixed;
top: 0;
left: 0;
height: 3px;
background: linear-gradient(90deg, var(--accent-1), var(--accent-2), var(--pink));
z-index: 9999; transition: width 0.1s; width: 0%;
z-index: 9999;
transition: width 0.1s;
width: 0%;
}
/* ── RESPONSIVE ────────────────────────────────────── */
@media(max-width: 720px) {
.hero { padding: 70px 0 50px; }
.hero-stats { gap: 24px; }
.projects-grid { grid-template-columns: 1fr; }
.nav-links { display: none; }
.footer-inner { flex-direction: column; text-align: center; }
.hero {
padding: 70px 0 50px;
}
.hero-stats {
gap: 24px;
}
.projects-grid {
grid-template-columns: 1fr;
}
.nav-links {
display: none;
}
.footer-inner {
flex-direction: column;
text-align: center;
}
}
</style>
</head>
<body>
<div class="scroll-indicator" id="scroll-bar"></div>
<canvas id="bg-canvas"></canvas>
<div class="grid-overlay"></div>
<div class="scroll-indicator" id="scroll-bar"></div>
<canvas id="bg-canvas"></canvas>
<div class="grid-overlay"></div>
<!-- ── NAV ────────────────────────────────────────────── -->
<nav>
<!-- ── NAV ────────────────────────────────────────────── -->
<nav>
<div class="nav-inner">
<a class="nav-brand" href="#">
<div class="nav-logo"><i class="fas fa-globe" style="color:#fff"></i></div>
@@ -344,17 +663,17 @@
2 Projects Online
</div>
</div>
</nav>
</nav>
<!-- ── HERO ───────────────────────────────────────────── -->
<section class="hero">
<!-- ── HERO ───────────────────────────────────────────── -->
<section class="hero">
<div class="wrapper">
<div class="hero-eyebrow">
<i class="fas fa-map-location-dot"></i>
Sistem Informasi Geografis
</div>
<h1 class="hero-title">
Portal <span class="gradient-text">WebGIS</span><br/>Kota Pontianak
Portal <span class="gradient-text">WebGIS</span><br />Kota Pontianak
</h1>
<p class="hero-sub">
Pusat akses seluruh project Sistem Informasi Geografis berbasis web untuk pengelolaan data spasial wilayah Kota Pontianak.
@@ -370,7 +689,7 @@
</div>
<div class="hero-stat">
<div class="hero-stat-num">PHP</div>
<div class="hero-stat-label"><?php echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION; ?></div>
<div class="hero-stat-label"><?php echo PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION; ?></div>
</div>
<div class="hero-stat">
<div class="hero-stat-num">GIS</div>
@@ -378,10 +697,10 @@
</div>
</div>
</div>
</section>
</section>
<!-- ── PROJECTS ────────────────────────────────────────── -->
<section id="projects">
<!-- ── PROJECTS ────────────────────────────────────────── -->
<section id="projects">
<div class="wrapper">
<div class="section-header">
<div class="section-label">Daftar Project</div>
@@ -438,7 +757,7 @@
<i class="fas fa-link"></i>
/Web GIS Layer/
</div>
<a href="http://localhost/Web%20GIS%20Layer/index.html"
<a href="./Web GIS Layer/index.html"
class="btn-open"
style="background:linear-gradient(135deg,#3b82f6,#06b6d4)"
onclick="window.location.href=this.href; return false;">
@@ -495,7 +814,7 @@
<i class="fas fa-link"></i>
/Web GIS Rumah Ibadah/
</div>
<a href="http://localhost/Web%20GIS%20Rumah%20Ibadah/index.html"
<a href="./Web GIS Rumah Ibadah/index.html"
class="btn-open"
style="background:linear-gradient(135deg,#8b5cf6,#ec4899)"
onclick="window.location.href=this.href; return false;">
@@ -527,10 +846,10 @@
</section>
</div><!-- /.wrapper -->
</section>
</section>
<!-- ── FOOTER ──────────────────────────────────────────── -->
<footer>
<!-- ── FOOTER ──────────────────────────────────────────── -->
<footer>
<div class="footer-inner">
<div class="footer-brand">
<div class="nav-logo" style="width:28px;height:28px;font-size:.8rem">
@@ -541,82 +860,113 @@
Dibangun dengan <span style="color:#ec4899">♥</span> menggunakan LeafletJS & PHP
</div>
</div>
</footer>
</footer>
<script>
/* ── ANIMATED PARTICLE CANVAS ─────────────────────────── */
(function() {
<script>
/* ── ANIMATED PARTICLE CANVAS ─────────────────────────── */
(function() {
const canvas = document.getElementById('bg-canvas');
const ctx = canvas.getContext('2d');
let W, H, particles = [];
function resize() { W = canvas.width = window.innerWidth; H = canvas.height = window.innerHeight; }
function resize() {
W = canvas.width = window.innerWidth;
H = canvas.height = window.innerHeight;
}
resize();
window.addEventListener('resize', resize);
class Particle {
constructor() { this.reset(); }
constructor() {
this.reset();
}
reset() {
this.x = Math.random() * W; this.y = Math.random() * H;
this.x = Math.random() * W;
this.y = Math.random() * H;
this.r = Math.random() * 1.5 + 0.3;
this.vx = (Math.random() - 0.5) * 0.25; this.vy = (Math.random() - 0.5) * 0.25;
this.vx = (Math.random() - 0.5) * 0.25;
this.vy = (Math.random() - 0.5) * 0.25;
this.a = Math.random() * 0.5 + 0.1;
const p = ['59,130,246','139,92,246','6,182,212','16,185,129'];
const p = ['59,130,246', '139,92,246', '6,182,212', '16,185,129'];
this.color = p[Math.floor(Math.random() * p.length)];
}
update() { this.x += this.vx; this.y += this.vy; if (this.x<0||this.x>W||this.y<0||this.y>H) this.reset(); }
draw() { ctx.beginPath(); ctx.arc(this.x,this.y,this.r,0,Math.PI*2); ctx.fillStyle=`rgba(${this.color},${this.a})`; ctx.fill(); }
update() {
this.x += this.vx;
this.y += this.vy;
if (this.x < 0 || this.x > W || this.y < 0 || this.y > H) this.reset();
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
ctx.fillStyle = `rgba(${this.color},${this.a})`;
ctx.fill();
}
}
for (let i = 0; i < 120; i++) particles.push(new Particle());
function drawLines() {
for (let i = 0; i < particles.length; i++)
for (let j = i+1; j < particles.length; j++) {
const dx=particles[i].x-particles[j].x, dy=particles[i].y-particles[j].y;
const d=Math.sqrt(dx*dx+dy*dy);
for (let j = i + 1; j < particles.length; j++) {
const dx = particles[i].x - particles[j].x,
dy = particles[i].y - particles[j].y;
const d = Math.sqrt(dx * dx + dy * dy);
if (d < 100) {
ctx.beginPath(); ctx.moveTo(particles[i].x,particles[i].y); ctx.lineTo(particles[j].x,particles[j].y);
ctx.strokeStyle=`rgba(59,130,246,${0.06*(1-d/100)})`; ctx.lineWidth=0.5; ctx.stroke();
ctx.beginPath();
ctx.moveTo(particles[i].x, particles[i].y);
ctx.lineTo(particles[j].x, particles[j].y);
ctx.strokeStyle = `rgba(59,130,246,${0.06*(1-d/100)})`;
ctx.lineWidth = 0.5;
ctx.stroke();
}
}
}
function animate() {
ctx.clearRect(0,0,W,H);
particles.forEach(p=>{p.update();p.draw();});
ctx.clearRect(0, 0, W, H);
particles.forEach(p => {
p.update();
p.draw();
});
drawLines();
requestAnimationFrame(animate);
}
animate();
})();
})();
/* ── SCROLL PROGRESS ──────────────────────────────────── */
window.addEventListener('scroll', () => {
/* ── SCROLL PROGRESS ──────────────────────────────────── */
window.addEventListener('scroll', () => {
const st = document.documentElement.scrollTop;
const sh = document.documentElement.scrollHeight - document.documentElement.clientHeight;
document.getElementById('scroll-bar').style.width = (st/sh*100) + '%';
});
document.getElementById('scroll-bar').style.width = (st / sh * 100) + '%';
});
/* ── CARD TILT ────────────────────────────────────────── */
document.querySelectorAll('.project-card').forEach(card => {
/* ── CARD TILT ────────────────────────────────────────── */
document.querySelectorAll('.project-card').forEach(card => {
card.addEventListener('mousemove', e => {
const r = card.getBoundingClientRect();
const x = ((e.clientX - r.left) / r.width - 0.5) * 8;
const y = ((e.clientY - r.top) / r.height - 0.5) * 8;
card.style.transform = `translateY(-6px) rotateX(${-y}deg) rotateY(${x}deg)`;
});
card.addEventListener('mouseleave', () => { card.style.transform = ''; });
});
card.addEventListener('mouseleave', () => {
card.style.transform = '';
});
});
/* ── INTERSECTION OBSERVER ────────────────────────────── */
const obs = new IntersectionObserver(entries => {
entries.forEach(e => { if (e.isIntersecting) e.target.style.animationPlayState = 'running'; });
}, { threshold: 0.1 });
document.querySelectorAll('.project-card,.tech-chip').forEach(el => {
/* ── INTERSECTION OBSERVER ────────────────────────────── */
const obs = new IntersectionObserver(entries => {
entries.forEach(e => {
if (e.isIntersecting) e.target.style.animationPlayState = 'running';
});
}, {
threshold: 0.1
});
document.querySelectorAll('.project-card,.tech-chip').forEach(el => {
el.style.animationPlayState = 'paused';
obs.observe(el);
});
</script>
});
</script>
</body>
</html>