Lompat ke konten
dokumentasi.id
Commit 493bd1c
v1
Star762

Kamu membaca versi lama. Halaman ini hanya bisa dibaca.

12

Website dan Playground

Website proyek ini adalah satu halaman Astro di rute tunggal. web/src/pages/index.astro merangkai lima section di bawah satu Layout, dan astro.config.mjs menetapkan site serta base /api-wilayah-indonesia/ (web/astro.config.mjs:7-10). README menautkan playground lewat anchor #playground pada halaman yang sama (README.md:475), jadi pengunjung yang ingin mencoba API langsung diarahkan ke section pertama, bukan ke halaman terpisah.

Satu rute, lima section

Urutan section di main bersifat tetap. Playground berada paling atas, lalu API, CLI, skill, dan FAQ (web/src/pages/index.astro:12-21). Bedanya hanya directive hidrasi: playground memakai client:only="react" (web/src/pages/index.astro:15), sedangkan section lain memakai client:load.

SectionKomponenAnchorDirectiveHalaman terkait
PlaygroundPlaygroundSectionplaygroundclient:only="react"halaman ini
APIApiSectionapiclient:loadReferensi Endpoint
CLICliSectioncliclient:loadCLI @emsifa/wilayah
SkillSkillSectionskillclient:loadSkill untuk AI Agent
FAQFaqSectionfaqclient:loadKelengkapan Data dan missings.json

Anchor cli dan skill masing-masing dipasang di section-nya (web/src/components/sections/CliSection.tsx:71, web/src/components/sections/SkillSection.tsx:22), dan anchor faq dipasang di section terakhir (web/src/components/sections/FaqSection.tsx:203). ApiSection memakai basis URL yang sama dengan playground, https://www.emsifa.com/api-wilayah-indonesia/v2 (web/src/components/sections/ApiSection.tsx:29-33).

⚠️ Karena playground memakai client:only="react", section itu tidak dirender saat build. Kalau JavaScript gagal dimuat, peta dan dropdown tidak muncul sama sekali, sementara section lain tetap tampil sebagai HTML.

State playground dan request bertingkat

PlaygroundSection menyimpan empat kode pilihan (provCode, regCode, distCode, villCode), enam daftar hasil fetch, dua detail terpilih, dan satu polygon multi-ring (web/src/components/sections/PlaygroundSection.tsx:66-93). Basis URL-nya konstanta absolut (web/src/components/sections/PlaygroundSection.tsx:8), sehingga astro dev di mesin lokal tetap memanggil API produksi.

Setiap tingkat punya efek sendiri: provinsi diambil sekali saat mount (web/src/components/sections/PlaygroundSection.tsx:95-121), regencies mengikuti provCode (web/src/components/sections/PlaygroundSection.tsx:123-154), districts mengikuti regCode (web/src/components/sections/PlaygroundSection.tsx:156-185), dan villages mengikuti distCode (web/src/components/sections/PlaygroundSection.tsx:187-216). Kecamatan dan kelurahan di-fetch sekali lagi untuk mendapat detail lengkap (web/src/components/sections/PlaygroundSection.tsx:218-252), lalu polygon diambil dari kode terdalam yang tersedia (web/src/components/sections/PlaygroundSection.tsx:254-279).

Berikut urutan request saat pengguna memilih wilayah, sampai peta bergerak dan polygon muncul.

sequenceDiagram
  actor User
  participant DD as RegionDropdowns
  participant PS as PlaygroundSection
  participant API as Static JSON v2
  participant Map as MapLibreIndonesiaMap
  User->>DD: pilih Provinsi
  DD->>PS: handleProv mengisi provCode
  PS->>PS: reset regCode distCode villCode
  PS->>API: GET /regencies/provCode.json
  API-->>PS: data daftar kabupaten kota
  PS->>PS: toRegion dan toRegionDetail
  PS->>Map: selectedForMap selectedDetail zoom
  Map->>Map: marker popup dan flyTo 1200 ms
  PS->>API: GET /paths/code.json
  API-->>PS: data path
  PS->>PS: normalizeRings menerima ring valid
  PS->>Map: polygon
  Map->>Map: addSource wilayah-polygon dan fitBounds
%% fig: Siklus request playground saat wilayah dipilih
%% desc: Pilihan dropdown memicu fetch daftar wilayah, lalu fetch paths, dan hasilnya diteruskan ke peta sebagai marker serta polygon.
Fig. 1: Siklus request playground saat wilayah dipilihPilihan dropdown memicu fetch daftar wilayah, lalu fetch paths, dan hasilnya diteruskan ke peta sebagai marker serta polygon.
PemicuRequestState yang diisi
mount komponenGET /provinces.jsonprovinces, provincesDetail
provCode terisiGET /regencies/{provCode}.jsonregencies, regenciesDetail
regCode terisiGET /districts/{regCode}.jsondistricts
distCode terisiGET /villages/{distCode}.jsonvillages
distCode terisiGET /districts/{distCode}.jsonselectedDist
villCode terisiGET /villages/{villCode}.jsonselectedVill
salah satu kode terisiGET /paths/{code}.jsonpolygon

Request yang sedang dipakai selalu ditampilkan di panel bawah sebagai tautan GET {dataUrl}, lengkap dengan durasi fetchMs (web/src/components/sections/PlaygroundSection.tsx:412-419, web/src/components/sections/PlaygroundSection.tsx:456-466). Efek-efek itu tidak memakai AbortController; pembatalan dilakukan dengan flag cancelled di dalam closure, seperti pada efek provinsi (web/src/components/sections/PlaygroundSection.tsx:95-121).

Di layar lebar, empat Select disusun sejajar dan dikunci berantai: kab/kota nonaktif tanpa provCode, kecamatan nonaktif tanpa regCode (web/src/components/playground/RegionDropdowns.tsx:391-416). Di layar sempit, MobileStackCarousel menggantinya dengan tumpukan kartu untuk empat level (web/src/components/playground/RegionDropdowns.tsx:84-89) yang memakai disabledByUnlock sebagai penentu kunci (web/src/components/playground/RegionDropdowns.tsx:208-213).

Pemilihan nilai langsung memajukan kartu aktif, dan efek lanjutan memajukan lagi ketika kode berubah (web/src/components/playground/RegionDropdowns.tsx:99-107, web/src/components/playground/RegionDropdowns.tsx:156-166). Kalau nilai tingkat atas dihapus, posisi aktif dijepit kembali ke langkah yang masih bisa dijangkau (web/src/components/playground/RegionDropdowns.tsx:137-145). Kartu bisa digeser; ambang geser 48 piksel menentukan pindah langkah (web/src/components/playground/RegionDropdowns.tsx:190-197).

stateDiagram-v2
  [*] --> Provinsi
  Provinsi --> Kabupaten: handleProv mengisi provCode
  Kabupaten --> Kecamatan: handleReg mengisi regCode
  Kecamatan --> Kelurahan: handleDist mengisi distCode
  Kabupaten --> Provinsi: handleProv mereset kode di bawahnya
  Kecamatan --> Kabupaten: handleReg mereset distCode dan villCode
  Kelurahan --> Kecamatan: handleDist mereset villCode
  classDef unlocked fill:#2d7d46,color:#fff
  classDef locked fill:#f59e0b,color:#000
  class Provinsi unlocked
  class Kabupaten,Kecamatan,Kelurahan locked
%% fig: Keadaan pilihan wilayah bertingkat
%% desc: Tingkat terdalam terbuka hanya setelah kode induknya terisi, dan memilih ulang tingkat atas mengosongkan kode di bawahnya.
Fig. 2: Keadaan pilihan wilayah bertingkatTingkat terdalam terbuka hanya setelah kode induknya terisi, dan memilih ulang tingkat atas mengosongkan kode di bawahnya.

Reset disediakan sebagai satu tombol di panel desktop. handleReset mengosongkan keempat kode sekaligus dan membuang polygon (web/src/components/sections/PlaygroundSection.tsx:327-349).

Peta MapLibre, tile ganda, dan polygon

Peta memakai MapLibre. Dua sumber tile tersedia: gaya vektor OSM_VECTOR_STYLE dari OpenFreeMap Liberty, dan gaya raster Esri World Imagery yang dibangun getEsriSatelliteStyle (web/src/components/playground/MapLibreIndonesiaMap.tsx:9-16, web/src/components/playground/MapLibreIndonesiaMap.tsx:43-65). Peta diinisialisasi sekali dengan pusat [118.0, -2.5] dan zoom 5 (web/src/components/playground/MapLibreIndonesiaMap.tsx:102-143). NavigationControl hanya dipasang di desktop lewat useIsMobile dengan breakpoint 768 piksel (web/src/components/playground/MapLibreIndonesiaMap.tsx:67-77).

Mengganti tile memanggil map.setStyle, yang menghapus source dan layer, lalu menambahkannya lagi setelah styledata; ada timer 300 ms sebagai jaring pengaman (web/src/components/playground/MapLibreIndonesiaMap.tsx:183-213). Marker dan popup dibangun ulang tiap kali wilayah terpilih berubah (web/src/components/playground/MapLibreIndonesiaMap.tsx:216-275), dan flyTo memakai durasi 1200 ms (web/src/components/playground/MapLibreIndonesiaMap.tsx:277-306).

Polygon digambar sebagai source wilayah-polygon dengan layer fill #10b981 beropasitas 0.18 dan layer garis #059669 selebar 2 (web/src/components/playground/MapLibreIndonesiaMap.tsx:346-371). Setelah polygon masuk, peta memanggil fitBounds dengan padding 24, maxZoom 19, dan durasi 1000 ms (web/src/components/playground/MapLibreIndonesiaMap.tsx:394-438).

AspekNilaiRujukan
Tile defaultosm (vektor Liberty)web/src/components/playground/MapLibreIndonesiaMap.tsx:9-16
Tile alternatifesri (raster World Imagery)web/src/components/playground/MapLibreIndonesiaMap.tsx:43-65
Durasi flyTo1200 msweb/src/components/playground/MapLibreIndonesiaMap.tsx:277-306
Warna fill polygon#10b981, opasitas 0.18web/src/components/playground/MapLibreIndonesiaMap.tsx:346-371
Padding fitBounds24, maxZoom 19web/src/components/playground/MapLibreIndonesiaMap.tsx:394-438

Zoom ditentukan dari tingkat terdalam yang terpilih: kelurahan 13, kecamatan 12, kab/kota 10, provinsi 8, dan 5 ketika belum ada pilihan (web/src/components/sections/PlaygroundSection.tsx:318). Target peta memakai prioritas kelurahan, kecamatan, kab/kota, lalu provinsi (web/src/components/sections/PlaygroundSection.tsx:281-304), dan seluruh nilai itu diteruskan ke komponen peta sebagai prop (web/src/components/sections/PlaygroundSection.tsx:353-361).

Normalisasi ring sebelum digambar

Bentuk path dari API tidak seragam kedalamannya, jadi playground menormalkannya lebih dulu. Komentar di mapUtils.ts mencatat tiga kasus: single ring kedalaman 2, multi ring kedalaman 3, dan penyarangan dalam seperti Papua Barat 92 pada kedalaman 4 (web/src/components/playground/mapUtils.ts:1-26). normalizeRings menelusuri node secara rekursif, dan hanya menyimpan ring dengan lebih dari dua titik (web/src/components/playground/mapUtils.ts:1-26).

Setelah normalisasi, toLngLat menukar pasangan [lat,lng] menjadi [lng,lat] karena MapLibre memakai urutan longitude lebih dulu (web/src/components/playground/mapUtils.ts:28-31). Helper ringsToGeoJSON juga tersedia untuk membangun FeatureCollection (web/src/components/playground/mapUtils.ts:33-46). Detail format path di response API dibahas di Polygon dan Boundary.

Kontrak data dan sisa dependensi

Playground memakai dua tipe: Region minimal dan RegionDetail yang menambahkan level 1 sampai 4 beserta capital, elv, tz, population, total_area, postal_code, has_path, dan objek induk (web/src/components/playground/types.ts:9-21). toRegion dan toRegionDetail memetakan response API ke tipe ini, dengan fallback lat/lng ke 0 ketika daftar tingkat kecamatan atau kelurahan tidak membawa koordinat (web/src/components/sections/PlaygroundSection.tsx:29-57).

Peta yang dipakai sekarang adalah MapLibre (web/src/components/sections/PlaygroundSection.tsx:353-361), tetapi leaflet dan react-leaflet masih tercatat sebagai dependency (web/package.json:21-26), dan stylesheet Leaflet 1.9.4 masih dimuat di head Layout.astro (web/src/layouts/Layout.astro:47-52). Halaman ini tidak menggambarkan isi playground/IndonesiaMap.tsx; yang pasti, ia bukan komponen yang dipasang di index.astro.

Build dan server pengembangan memakai skrip Astro standar: dev, build, preview, dan astro (web/package.json:8-13). Dependensi runtime mencakup astro, @astrojs/react, tailwindcss, maplibre-gl, framer-motion, lucide-react, dan highlight.js (web/package.json:14-28). Langkah build dan deploy situs ini dibahas di Deploy dan CI.