add all project files

This commit is contained in:
2026-06-10 16:49:48 +07:00
parent 319d7f0996
commit 19d7bbf798
21 changed files with 3146 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
FROM php:8.2-apache
# Install ekstensi mysqli untuk koneksi ke database
RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli
# Aktifkan mod_rewrite Apache (berguna untuk URL yang bersih/routing)
RUN a2enmod rewrite
# Update permissions
RUN chown -R www-data:www-data /var/www/html
File diff suppressed because one or more lines are too long
+21
View File
@@ -0,0 +1,21 @@
<?php
mysqli_report(MYSQLI_REPORT_OFF);
$host = getenv("DB_HOST") ?: "localhost";
$user = "root";
$pass = "fira123";
$db = "webgis"; // Menggunakan database sendiri sesuai setup_webgis.sql
$conn = new mysqli($host, $user, $pass, $db);
if ($conn->connect_error) {
header('Content-Type: application/json');
die(json_encode([
"status" => "error",
"message" => "Koneksi database gagal",
"detail" => $conn->connect_error
]));
}
$conn->set_charset('utf8mb4');
?>
+21
View File
@@ -0,0 +1,21 @@
<?php
include "db_config.php";
header('Content-Type: application/json');
$data = json_decode(file_get_contents("php://input"), true);
$id = isset($data['id']) ? intval($data['id']) : 0;
if ($id <= 0) {
echo json_encode(["status" => "error", "message" => "ID tidak valid"]);
exit;
}
$sql = "DELETE FROM spbu WHERE id=$id";
if ($conn->query($sql)) {
echo json_encode(["status" => "success"]);
} else {
echo json_encode(["status" => "error", "message" => $conn->error]);
}
?>
+21
View File
@@ -0,0 +1,21 @@
<?php
include "db_config.php";
header('Content-Type: application/json');
$data = json_decode(file_get_contents("php://input"), true);
$id = isset($data['id']) ? intval($data['id']) : 0;
if ($id <= 0) {
echo json_encode(["status" => "error", "message" => "ID tidak valid"]);
exit;
}
$sql = "DELETE FROM jalan WHERE id=$id";
if ($conn->query($sql)) {
echo json_encode(["status" => "success"]);
} else {
echo json_encode(["status" => "error", "message" => $conn->error]);
}
?>
+21
View File
@@ -0,0 +1,21 @@
<?php
include "db_config.php";
header('Content-Type: application/json');
$data = json_decode(file_get_contents("php://input"), true);
$id = isset($data['id']) ? intval($data['id']) : 0;
if ($id <= 0) {
echo json_encode(["status" => "error", "message" => "ID tidak valid"]);
exit;
}
$sql = "DELETE FROM parsil WHERE id=$id";
if ($conn->query($sql)) {
echo json_encode(["status" => "success"]);
} else {
echo json_encode(["status" => "error", "message" => $conn->error]);
}
?>
+25
View File
@@ -0,0 +1,25 @@
<?php
include "db_config.php";
header('Content-Type: application/json');
$sql = "SELECT * FROM spbu";
$result = $conn->query($sql);
if (!$result) {
echo json_encode([
"status" => "error",
"message" => "Gagal membaca tabel spbu",
"detail" => $conn->error
]);
exit;
}
$data = [];
while($row = $result->fetch_assoc()){
$data[] = $row;
}
echo json_encode($data);
?>
+25
View File
@@ -0,0 +1,25 @@
<?php
include "db_config.php";
header('Content-Type: application/json');
$sql = "SELECT * FROM jalan";
$result = $conn->query($sql);
if (!$result) {
echo json_encode([
"status" => "error",
"message" => "Gagal membaca tabel jalan",
"detail" => $conn->error
]);
exit;
}
$data = [];
while($row = $result->fetch_assoc()){
$data[] = $row;
}
echo json_encode($data);
?>
+25
View File
@@ -0,0 +1,25 @@
<?php
include "db_config.php";
header('Content-Type: application/json');
$sql = "SELECT * FROM parsil";
$result = $conn->query($sql);
if (!$result) {
echo json_encode([
"status" => "error",
"message" => "Gagal membaca tabel parsil",
"detail" => $conn->error
]);
exit;
}
$data = [];
while($row = $result->fetch_assoc()){
$data[] = $row;
}
echo json_encode($data);
?>
+24
View File
@@ -0,0 +1,24 @@
<?php
include "db_config.php";
$data = json_decode(file_get_contents("php://input"), true);
$nama = $conn->real_escape_string($data['nama']);
$no = $conn->real_escape_string($data['no']);
$status = $conn->real_escape_string($data['status']);
$alamat = isset($data['alamat']) ? $conn->real_escape_string($data['alamat']) : '';
$lat = $data['lat'];
$lng = $data['lng'];
$sql = "INSERT INTO spbu (nama,no,status,alamat,lat,lng)
VALUES ('$nama','$no','$status','$alamat','$lat','$lng')";
if($conn->query($sql)){
echo json_encode([
"status"=>"success",
"id"=>$conn->insert_id
]);
}else{
echo json_encode(["status"=>"error", "msg"=>$conn->error]);
}
?>
+34
View File
@@ -0,0 +1,34 @@
<?php
include "db_config.php";
header('Content-Type: application/json');
$data = json_decode(file_get_contents("php://input"), true);
$nama = $data['nama'];
$status = $data['status'];
$panjang = $data['panjang'];
$koordinatInput = $data['koordinat'] ?? [];
if (is_string($koordinatInput)) {
$decoded = json_decode($koordinatInput, true);
$koordinat = (json_last_error() === JSON_ERROR_NONE) ? json_encode($decoded) : '[]';
} else {
$koordinat = json_encode($koordinatInput);
}
$sql = "INSERT INTO jalan (nama,status,panjang,koordinat)
VALUES ('$nama','$status','$panjang','$koordinat')";
if($conn->query($sql)){
echo json_encode([
"status"=>"success",
"id"=>$conn->insert_id
]);
}else{
echo json_encode([
"status"=>"error",
"error"=>$conn->error
]);
}
?>
+37
View File
@@ -0,0 +1,37 @@
<?php
include "db_config.php";
header('Content-Type: application/json');
$data = json_decode(file_get_contents("php://input"), true);
$nama = $data['nama'];
$pemilik = $data['pemilik'];
$status = $data['status'];
$luas = $data['luas'];
$koordinatInput = $data['koordinat'] ?? [];
if (is_string($koordinatInput)) {
$decoded = json_decode($koordinatInput, true);
$koordinat = (json_last_error() === JSON_ERROR_NONE) ? json_encode($decoded) : '[]';
} else {
$koordinat = json_encode($koordinatInput);
}
$sql = "INSERT INTO parsil
(nama, pemilik, status, luas, koordinat)
VALUES
('$nama','$pemilik','$status','$luas','$koordinat')";
if($conn->query($sql)){
echo json_encode([
"status"=>"success",
"id"=>$conn->insert_id
]);
}else{
echo json_encode([
"status"=>"error",
"message"=>$conn->error
]);
}
?>
+68
View File
@@ -0,0 +1,68 @@
CREATE DATABASE IF NOT EXISTS webgis
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
USE webgis;
CREATE TABLE IF NOT EXISTS spbu (
id INT AUTO_INCREMENT PRIMARY KEY,
nama VARCHAR(200) NOT NULL,
no VARCHAR(60) NOT NULL,
status ENUM('Ya','Tidak') NOT NULL DEFAULT 'Tidak',
lat DECIMAL(10,7) NOT NULL,
lng DECIMAL(10,7) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS jalan (
id INT AUTO_INCREMENT PRIMARY KEY,
nama VARCHAR(200) NOT NULL,
status ENUM('Nasional','Provinsi','Kabupaten') NOT NULL DEFAULT 'Kabupaten',
panjang DECIMAL(12,2) NOT NULL DEFAULT 0,
koordinat LONGTEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS parsil (
id INT AUTO_INCREMENT PRIMARY KEY,
nama VARCHAR(200) NOT NULL,
pemilik VARCHAR(200) NOT NULL,
status ENUM('SHM','HGB','Sewa','Lainnya') NOT NULL DEFAULT 'SHM',
luas DECIMAL(14,2) NOT NULL DEFAULT 0,
koordinat LONGTEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS kemiskinan (
id INT AUTO_INCREMENT PRIMARY KEY,
nama_kk VARCHAR(200) NOT NULL,
jumlah_kk INT NOT NULL DEFAULT 1,
alamat TEXT NOT NULL,
lat DECIMAL(10,7) NOT NULL,
lng DECIMAL(10,7) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS masjid (
id INT AUTO_INCREMENT PRIMARY KEY,
nama_masjid VARCHAR(200) NOT NULL,
pic_masjid VARCHAR(200) NOT NULL,
alamat_masjid TEXT NOT NULL,
radius INT NOT NULL DEFAULT 500,
lat DECIMAL(10,7) NOT NULL,
lng DECIMAL(10,7) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `spbu` (`nama`, `no`, `status`, `lat`, `lng`) VALUES
('SPBU Ahmad Yani', '64.781.01', 'Ya', -0.043513, 109.336423),
('SPBU Komyos Sudarso', '64.781.18', 'Tidak', -0.015243, 109.317540),
('SPBU Kapuas Indah', '64.781.14', 'Ya', -0.027581, 109.360541),
('SPBU Imam Bonjol', '64.781.19', 'Tidak', -0.038180, 109.349692),
('SPBU Gajah Mada', '64.781.11', 'Ya', -0.032159, 109.343513),
('SPBU Sungai Jawi', '64.781.05', 'Tidak', -0.021589, 109.320491),
('SPBU Siantan', '64.781.12', 'Ya', 0.007519, 109.336492);
+28
View File
@@ -0,0 +1,28 @@
<?php
include "db_config.php";
header('Content-Type: application/json');
$data = json_decode(file_get_contents("php://input"), true);
$id = isset($data['id']) ? intval($data['id']) : 0;
$nama = $conn->real_escape_string($data['nama'] ?? '');
$no = $conn->real_escape_string($data['no'] ?? '');
$status = $conn->real_escape_string($data['status'] ?? 'Tidak');
$alamat = $conn->real_escape_string($data['alamat'] ?? '');
$lat = isset($data['lat']) ? floatval($data['lat']) : 0;
$lng = isset($data['lng']) ? floatval($data['lng']) : 0;
if ($id <= 0 || $nama === '' || $no === '') {
echo json_encode(["status" => "error", "message" => "Data tidak valid"]);
exit;
}
$sql = "UPDATE spbu SET nama='$nama', no='$no', status='$status', alamat='$alamat', lat='$lat', lng='$lng' WHERE id=$id";
if ($conn->query($sql)) {
echo json_encode(["status" => "success"]);
} else {
echo json_encode(["status" => "error", "message" => $conn->error]);
}
?>
+35
View File
@@ -0,0 +1,35 @@
<?php
include "db_config.php";
header('Content-Type: application/json');
$data = json_decode(file_get_contents("php://input"), true);
$id = isset($data['id']) ? intval($data['id']) : 0;
$nama = $conn->real_escape_string($data['nama'] ?? '');
$status = $conn->real_escape_string($data['status'] ?? 'Kabupaten');
$panjang = isset($data['panjang']) ? floatval($data['panjang']) : 0;
$koordinatInput = $data['koordinat'] ?? [];
if ($id <= 0 || $nama === '') {
echo json_encode(["status" => "error", "message" => "Data tidak valid"]);
exit;
}
if (is_string($koordinatInput)) {
$decoded = json_decode($koordinatInput, true);
$koordinat = (json_last_error() === JSON_ERROR_NONE) ? json_encode($decoded) : '[]';
} else {
$koordinat = json_encode($koordinatInput);
}
$koordinat = $conn->real_escape_string($koordinat);
$sql = "UPDATE jalan SET nama='$nama', status='$status', panjang='$panjang', koordinat='$koordinat' WHERE id=$id";
if ($conn->query($sql)) {
echo json_encode(["status" => "success"]);
} else {
echo json_encode(["status" => "error", "message" => $conn->error]);
}
?>
+36
View File
@@ -0,0 +1,36 @@
<?php
include "db_config.php";
header('Content-Type: application/json');
$data = json_decode(file_get_contents("php://input"), true);
$id = isset($data['id']) ? intval($data['id']) : 0;
$nama = $conn->real_escape_string($data['nama'] ?? '');
$pemilik = $conn->real_escape_string($data['pemilik'] ?? '');
$status = $conn->real_escape_string($data['status'] ?? 'SHM');
$luas = isset($data['luas']) ? floatval($data['luas']) : 0;
$koordinatInput = $data['koordinat'] ?? [];
if ($id <= 0 || $nama === '') {
echo json_encode(["status" => "error", "message" => "Data tidak valid"]);
exit;
}
if (is_string($koordinatInput)) {
$decoded = json_decode($koordinatInput, true);
$koordinat = (json_last_error() === JSON_ERROR_NONE) ? json_encode($decoded) : '[]';
} else {
$koordinat = json_encode($koordinatInput);
}
$koordinat = $conn->real_escape_string($koordinat);
$sql = "UPDATE parsil SET nama='$nama', pemilik='$pemilik', status='$status', luas='$luas', koordinat='$koordinat' WHERE id=$id";
if ($conn->query($sql)) {
echo json_encode(["status" => "success"]);
} else {
echo json_encode(["status" => "error", "message" => $conn->error]);
}
?>
+2160
View File
File diff suppressed because it is too large Load Diff
+31
View File
@@ -0,0 +1,31 @@
version: '3.8'
services:
web:
build: .
ports:
- "8080:80"
volumes:
- ./:/var/www/html
environment:
- DB_HOST=db
depends_on:
- db
db:
image: mysql:8.0
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: fira123
MYSQL_DATABASE: webgis
ports:
- "3307:3306"
volumes:
- db_data:/var/lib/mysql
# Script ini akan otomatis dijalankan oleh MySQL saat pertama kali menyala (hanya untuk setup awal)
- ./WEBGIS/01/api/setup_webgis.sql:/docker-entrypoint-initdb.d/1_setup_webgis.sql
- ./webtugas/01/api/setup_webtugas.sql:/docker-entrypoint-initdb.d/2_setup_webtugas.sql
volumes:
db_data:
+507
View File
@@ -0,0 +1,507 @@
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebGIS Portal — Sistem Informasi Geografis</title>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--cyan: #06b6d4;
--cyan-dark: #0891b2;
--violet: #8b5cf6;
--violet-dark: #7c3aed;
--blue: #3b82f6;
--slate-50: #f8fafc;
--slate-100: #f1f5f9;
--slate-200: #e2e8f0;
--slate-400: #94a3b8;
--slate-500: #64748b;
--slate-700: #334155;
--slate-900: #0f172a;
}
html { scroll-behavior: smooth; }
body {
font-family: 'Plus Jakarta Sans', sans-serif;
background: var(--slate-50);
color: var(--slate-900);
min-height: 100vh;
overflow-x: hidden;
}
/* ── BACKGROUND ─────────────────────────────── */
.bg-layer {
position: fixed;
inset: 0;
z-index: 0;
pointer-events: none;
overflow: hidden;
}
.orb {
position: absolute;
border-radius: 50%;
filter: blur(90px);
mix-blend-mode: multiply;
opacity: .55;
animation: float 8s ease-in-out infinite;
}
.orb-1 { width: 520px; height: 520px; background: #a5f3fc; top: -120px; left: -120px; animation-delay: 0s; }
.orb-2 { width: 440px; height: 440px; background: #ddd6fe; top: 30%; right: -80px; animation-delay: -3s; }
.orb-3 { width: 360px; height: 360px; background: #bfdbfe; bottom: -80px; left: 30%; animation-delay: -5s; }
@keyframes float {
0%, 100% { transform: translate(0, 0) scale(1); }
33% { transform: translate(25px, -35px) scale(1.06); }
66% { transform: translate(-18px, 22px) scale(.95); }
}
/* grid mesh overlay */
.mesh {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(148,163,184,.12) 1px, transparent 1px),
linear-gradient(90deg, rgba(148,163,184,.12) 1px, transparent 1px);
background-size: 60px 60px;
}
/* ── LAYOUT ─────────────────────────────── */
.wrapper {
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
padding: 24px 24px 64px;
}
/* ── NAVBAR ─────────────────────────────── */
nav {
width: 100%;
max-width: 780px;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 24px;
}
.nav-logo {
display: flex;
align-items: center;
gap: 10px;
}
.nav-icon {
width: 38px; height: 38px;
background: linear-gradient(135deg, var(--cyan), var(--blue));
border-radius: 10px;
display: flex; align-items: center; justify-content: center;
box-shadow: 0 4px 14px rgba(6,182,212,.35);
}
.nav-icon svg { width: 20px; height: 20px; color: white; }
.nav-brand {
font-size: 1.05rem;
font-weight: 700;
letter-spacing: -.01em;
color: var(--slate-900);
}
.nav-brand span { color: var(--cyan-dark); }
/* ── HERO ─────────────────────────────── */
.hero {
text-align: center;
max-width: 600px;
margin-bottom: 40px;
}
.hero-eyebrow {
display: inline-flex;
align-items: center;
gap: 8px;
background: white;
border: 1px solid var(--slate-200);
border-radius: 99px;
padding: 6px 16px 6px 8px;
margin-bottom: 28px;
box-shadow: 0 2px 8px rgba(0,0,0,.06);
}
.hero-dot {
width: 26px; height: 26px;
background: linear-gradient(135deg, #ecfeff, #cffafe);
border-radius: 50%;
display: flex; align-items: center; justify-content: center;
}
.pulse {
width: 8px; height: 8px;
background: var(--cyan);
border-radius: 50%;
box-shadow: 0 0 0 0 rgba(6,182,212,.5);
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(6,182,212,.6); }
70% { box-shadow: 0 0 0 8px rgba(6,182,212,0); }
100% { box-shadow: 0 0 0 0 rgba(6,182,212,0); }
}
.hero-eyebrow-text {
font-size: .78rem;
font-weight: 600;
letter-spacing: .06em;
text-transform: uppercase;
color: var(--slate-500);
}
.hero-title {
font-size: clamp(2.6rem, 6vw, 4rem);
font-weight: 800;
line-height: 1.1;
letter-spacing: -.03em;
margin-bottom: 20px;
}
.hero-title .gradient {
background: linear-gradient(135deg, var(--cyan-dark) 0%, var(--blue) 50%, var(--violet) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero-desc {
font-size: 1.05rem;
color: var(--slate-500);
line-height: 1.75;
font-weight: 400;
}
/* ── DIVIDER ─────────────────────────────── */
.section-label {
display: flex;
align-items: center;
gap: 16px;
width: 100%;
max-width: 780px;
margin-bottom: 24px;
}
.section-label::before, .section-label::after {
content: '';
flex: 1;
height: 1px;
background: var(--slate-200);
}
.section-label-text {
font-size: .72rem;
font-weight: 700;
letter-spacing: .12em;
text-transform: uppercase;
color: var(--slate-400);
white-space: nowrap;
}
/* ── CARDS ─────────────────────────────── */
.cards {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
width: 100%;
max-width: 780px;
}
.card {
display: flex;
flex-direction: column;
background: white;
border: 1.5px solid var(--slate-200);
border-radius: 28px;
padding: 32px;
text-decoration: none;
color: inherit;
transition: transform .35s cubic-bezier(.34,1.56,.64,1), box-shadow .35s ease, border-color .25s ease;
position: relative;
overflow: hidden;
}
.card::before {
content: '';
position: absolute;
inset: 0;
opacity: 0;
transition: opacity .35s ease;
border-radius: 28px;
}
.card-1::before { background: linear-gradient(135deg, rgba(6,182,212,.04), rgba(59,130,246,.04)); }
.card-2::before { background: linear-gradient(135deg, rgba(139,92,246,.04), rgba(236,72,153,.04)); }
.card:hover {
transform: translateY(-8px) scale(1.01);
}
.card-1:hover {
border-color: rgba(6,182,212,.4);
box-shadow: 0 24px 60px -12px rgba(6,182,212,.22), 0 8px 20px rgba(0,0,0,.06);
}
.card-2:hover {
border-color: rgba(139,92,246,.4);
box-shadow: 0 24px 60px -12px rgba(139,92,246,.22), 0 8px 20px rgba(0,0,0,.06);
}
.card:hover::before { opacity: 1; }
/* card top bar accent */
.card-accent {
position: absolute;
top: 0; left: 32px; right: 32px;
height: 2px;
border-radius: 0 0 4px 4px;
transform: scaleX(0);
transition: transform .4s cubic-bezier(.34,1.56,.64,1);
transform-origin: left;
}
.card:hover .card-accent { transform: scaleX(1); }
.card-1 .card-accent { background: linear-gradient(90deg, var(--cyan), var(--blue)); }
.card-2 .card-accent { background: linear-gradient(90deg, var(--violet), #ec4899); }
/* icon */
.card-icon-wrap {
width: 58px; height: 58px;
border-radius: 16px;
display: flex; align-items: center; justify-content: center;
margin-bottom: 24px;
transition: transform .35s cubic-bezier(.34,1.56,.64,1);
}
.card:hover .card-icon-wrap { transform: scale(1.12) rotate(-4deg); }
.card-1 .card-icon-wrap {
background: linear-gradient(135deg, #ecfeff, #cffafe);
border: 1.5px solid rgba(6,182,212,.25);
}
.card-2 .card-icon-wrap {
background: linear-gradient(135deg, #f5f3ff, #ede9fe);
border: 1.5px solid rgba(139,92,246,.25);
}
.card-1 .card-icon-wrap svg { color: var(--cyan-dark); width: 28px; height: 28px; }
.card-2 .card-icon-wrap svg { color: var(--violet); width: 28px; height: 28px; }
/* tag */
.card-tag {
display: inline-flex;
align-items: center;
gap: 5px;
font-size: .7rem;
font-weight: 700;
letter-spacing: .1em;
text-transform: uppercase;
padding: 3px 10px;
border-radius: 99px;
margin-bottom: 10px;
width: fit-content;
}
.card-1 .card-tag { background: #ecfeff; color: var(--cyan-dark); }
.card-2 .card-tag { background: #f5f3ff; color: var(--violet-dark); }
.card-title {
font-size: 1.45rem;
font-weight: 700;
letter-spacing: -.02em;
line-height: 1.2;
margin-bottom: 12px;
}
.card-desc {
font-size: .9rem;
color: var(--slate-500);
line-height: 1.7;
flex-grow: 1;
margin-bottom: 28px;
}
/* pills */
.card-pills {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-bottom: 24px;
}
.pill {
font-size: .7rem;
font-weight: 600;
padding: 3px 10px;
border-radius: 99px;
background: var(--slate-100);
color: var(--slate-500);
border: 1px solid var(--slate-200);
}
/* cta */
.card-cta {
display: flex;
align-items: center;
gap: 8px;
font-size: .88rem;
font-weight: 700;
border-radius: 99px;
padding: 12px 22px;
border: none;
cursor: pointer;
transition: gap .3s ease, box-shadow .3s ease;
}
.card:hover .card-cta { gap: 14px; }
.card-1 .card-cta {
background: linear-gradient(135deg, var(--cyan), var(--blue));
color: white;
box-shadow: 0 6px 20px rgba(6,182,212,.3);
}
.card-1:hover .card-cta { box-shadow: 0 8px 28px rgba(6,182,212,.45); }
.card-2 .card-cta {
background: linear-gradient(135deg, var(--violet), #a855f7);
color: white;
box-shadow: 0 6px 20px rgba(139,92,246,.3);
}
.card-2:hover .card-cta { box-shadow: 0 8px 28px rgba(139,92,246,.45); }
.cta-arrow { transition: transform .3s ease; }
.card:hover .cta-arrow { transform: translateX(4px); }
/* ── FOOTER ─────────────────────────────── */
footer {
margin-top: 48px;
text-align: center;
font-size: .78rem;
color: var(--slate-400);
font-weight: 500;
}
/* ── RESPONSIVE ─────────────────────────── */
@media (max-width: 640px) {
.cards { grid-template-columns: 1fr; }
nav { flex-direction: column; gap: 12px; }
}
</style>
</head>
<body>
<div class="bg-layer">
<div class="mesh"></div>
<div class="orb orb-1"></div>
<div class="orb orb-2"></div>
<div class="orb orb-3"></div>
</div>
<div class="wrapper">
<!-- NAVBAR -->
<nav>
<div class="nav-logo">
<div class="nav-icon">
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7" />
</svg>
</div>
<span class="nav-brand">Web<span>GIS</span></span>
</div>
</nav>
<!-- HERO -->
<div class="hero">
<div class="hero-eyebrow">
<div class="hero-dot"><div class="pulse"></div></div>
<span class="hero-eyebrow-text">Sistem Aktif &amp; Berjalan</span>
</div>
<h1 class="hero-title">
Portal Pemetaan<br>
<span class="gradient">Spasial Digital</span>
</h1>
<p class="hero-desc">
Platform terpadu untuk eksplorasi data geografis Kota Pontianak.<br>
Pilih project di bawah ini untuk mulai menjelajah.
</p>
</div>
<!-- SECTION LABEL -->
<div class="section-label">
<span class="section-label-text">Pilih Project</span>
</div>
<!-- CARDS -->
<div class="cards">
<!-- Card 1 -->
<a href="WEBGIS/01/" class="card card-1">
<div class="card-accent"></div>
<div class="card-icon-wrap">
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.8">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<div class="card-tag">Project 01</div>
<h2 class="card-title">Sistem Tata<br>Ruang Kota</h2>
<p class="card-desc">
Pemetaan komprehensif Point of Interest SPBU, jaringan jalan, dan parsil tanah berbasis administrasi kecamatan Kota Pontianak.
</p>
<div class="card-pills">
<span class="pill">📍 SPBU & POI</span>
<span class="pill">🛣️ Jaringan Jalan</span>
<span class="pill">🗺️ Parsil Tanah</span>
</div>
<div class="card-cta">
Buka Project
<svg class="cta-arrow" width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M17 8l4 4m0 0l-4 4m4-4H3" />
</svg>
</div>
</a>
<!-- Card 2 -->
<a href="webtugas/01/" class="card card-2">
<div class="card-accent"></div>
<div class="card-icon-wrap">
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.8">
<path stroke-linecap="round" stroke-linejoin="round" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
</div>
<div class="card-tag">Project 02</div>
<h2 class="card-title">SiPetaSos<br><span style="font-weight:500;opacity:.6;font-size:1rem">Peta Sosial</span></h2>
<p class="card-desc">
Sistem informasi pemetaan kemiskinan berbasis Rumah Ibadah. Visualisasi sebaran KK miskin, ekstrem, dan blank spot layanan sosial.
</p>
<div class="card-pills">
<span class="pill">👥 Data KK Miskin</span>
<span class="pill">🕌 Rumah Ibadah</span>
<span class="pill">📊 Laporan</span>
</div>
<div class="card-cta">
Buka Project
<svg class="cta-arrow" width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M17 8l4 4m0 0l-4 4m4-4H3" />
</svg>
</div>
</a>
</div>
<!-- FOOTER -->
<footer>
&copy; 2026 WebGIS Portal &mdash; Sistem Informasi Geografis Kota Pontianak
</footer>
</div>
</body>
</html>
+8
View File
@@ -0,0 +1,8 @@
INSERT INTO `spbu` (`nama`, `no`, `status`, `lat`, `lng`) VALUES
('SPBU Ahmad Yani', '64.781.01', 'Ya', -0.043513, 109.336423),
('SPBU Komyos Sudarso', '64.781.18', 'Tidak', -0.015243, 109.317540),
('SPBU Kapuas Indah', '64.781.14', 'Ya', -0.027581, 109.360541),
('SPBU Imam Bonjol', '64.781.19', 'Tidak', -0.038180, 109.349692),
('SPBU Gajah Mada', '64.781.11', 'Ya', -0.032159, 109.343513),
('SPBU Sungai Jawi', '64.781.05', 'Tidak', -0.021589, 109.320491),
('SPBU Siantan', '64.781.12', 'Ya', 0.007519, 109.336492);
Submodule
+1
Submodule webtugas added at 30b16bb877