|
714 | 714 | animation: fadeIn 0.3s; |
715 | 715 | } |
716 | 716 |
|
| 717 | + /* Search Playground */ |
| 718 | + .search-row { |
| 719 | + display: flex; |
| 720 | + gap: 12px; |
| 721 | + align-items: center; |
| 722 | + flex-wrap: wrap; |
| 723 | + margin-top: 14px; |
| 724 | + } |
| 725 | + |
| 726 | + .search-input { |
| 727 | + flex: 1; |
| 728 | + min-width: 220px; |
| 729 | + padding: 14px 16px; |
| 730 | + background: var(--dark-lighter); |
| 731 | + border: 1px solid rgba(255, 255, 255, 0.1); |
| 732 | + border-radius: 12px; |
| 733 | + color: var(--text); |
| 734 | + font-size: 0.95em; |
| 735 | + font-weight: 500; |
| 736 | + outline: none; |
| 737 | + transition: all 0.3s; |
| 738 | + } |
| 739 | + |
| 740 | + .search-input::placeholder { |
| 741 | + color: rgba(148, 163, 184, 0.8); |
| 742 | + } |
| 743 | + |
| 744 | + .search-input:focus { |
| 745 | + border-color: var(--primary); |
| 746 | + box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.12); |
| 747 | + } |
| 748 | + |
| 749 | + .helper-note { |
| 750 | + margin-top: 12px; |
| 751 | + font-size: 0.9em; |
| 752 | + color: var(--text-muted); |
| 753 | + } |
| 754 | + |
| 755 | + .helper-note strong { |
| 756 | + color: var(--text); |
| 757 | + } |
| 758 | + |
717 | 759 | /* Branding Section */ |
718 | 760 | .branding-section { |
719 | 761 | padding: 80px 40px; |
@@ -1218,6 +1260,7 @@ <h2>Try It Live</h2> |
1218 | 1260 | <button class="endpoint-tab" onclick="selectEndpoint('regencies')">Regencies</button> |
1219 | 1261 | <button class="endpoint-tab" onclick="selectEndpoint('districts')">Districts</button> |
1220 | 1262 | <button class="endpoint-tab" onclick="selectEndpoint('villages')">Villages</button> |
| 1263 | + <button class="endpoint-tab" onclick="selectEndpoint('search')">Search</button> |
1221 | 1264 | </div> |
1222 | 1265 | </div> |
1223 | 1266 |
|
@@ -1286,6 +1329,29 @@ <h2>Try It Live</h2> |
1286 | 1329 | </button> |
1287 | 1330 | </div> |
1288 | 1331 |
|
| 1332 | + <div id="endpoint-search" class="endpoint-content" style="display:none;"> |
| 1333 | + <div class="request-block"> |
| 1334 | + <div class="request-label">REQUEST</div> |
| 1335 | + <div class="request-url"> |
| 1336 | + <span class="method-badge">GET</span> |
| 1337 | + <span class="url-text" id="url-search">https://konoland-api.vercel.app/search?q=jakarta</span> |
| 1338 | + <button class="copy-icon" onclick="copyUrl('url-search')"><i class="far fa-copy"></i></button> |
| 1339 | + </div> |
| 1340 | + </div> |
| 1341 | + |
| 1342 | + <div class="search-row"> |
| 1343 | + <input id="search-q" class="search-input" type="text" placeholder="Type a name (e.g., jakarta, aceh, bandung, teupah)..." autocomplete="off" /> |
| 1344 | + <button class="btn btn-primary" id="search-run-btn" onclick="trySearch()"> |
| 1345 | + <span id="loading-search" style="display:none;" class="spinner"></span> |
| 1346 | + <span id="text-search">Run Request</span> |
| 1347 | + </button> |
| 1348 | + </div> |
| 1349 | + |
| 1350 | + <div class="helper-note" id="search-helper-note"> |
| 1351 | + Returns typed results: <strong>province</strong> / <strong>regency</strong> / <strong>district</strong> / <strong>village</strong>. |
| 1352 | + </div> |
| 1353 | + </div> |
| 1354 | + |
1289 | 1355 | <div id="response-block" class="response-block"> |
1290 | 1356 | <pre id="response-content"></pre> |
1291 | 1357 | </div> |
@@ -1354,6 +1420,7 @@ <h2><i class="fas fa-coffee"></i> Support This Project</h2> |
1354 | 1420 | function apiRegenciesUrl(code) { return USE_STATIC_API ? ('api/regencies/' + code + '.json') : (API_BASE + '/regency?provinceCode=' + code + '&limit=200&sortBy=regency'); } |
1355 | 1421 | function apiDistrictsUrl(code) { return USE_STATIC_API ? ('api/districts/' + code + '.json') : (API_BASE + '/district?regencyCode=' + code + '&limit=200&sortBy=district'); } |
1356 | 1422 | function apiVillagesUrl(code) { return USE_STATIC_API ? ('api/villages/' + code + '.json') : (API_BASE + '/village?districtCode=' + code + '&limit=500&sortBy=village'); } |
| 1423 | + function apiSearchUrl(q) { return API_BASE + '/search?q=' + encodeURIComponent(q); } |
1357 | 1424 | function apiTryEndpointUrl(endpoint) { |
1358 | 1425 | if (!USE_STATIC_API) return API_BASE + '/' + endpoint; |
1359 | 1426 | if (endpoint.startsWith('province')) return 'api/provinces.json'; |
@@ -1402,6 +1469,25 @@ <h2><i class="fas fa-coffee"></i> Support This Project</h2> |
1402 | 1469 | if (document.getElementById('url-regencies')) document.getElementById('url-regencies').textContent = USE_STATIC_API ? (base + '/api/regencies/11.json') : (API_BASE + '/regency?provinceCode=11&limit=5'); |
1403 | 1470 | if (document.getElementById('url-districts')) document.getElementById('url-districts').textContent = USE_STATIC_API ? (base + '/api/districts/1101.json') : (API_BASE + '/district?regencyCode=1101&limit=5'); |
1404 | 1471 | if (document.getElementById('url-villages')) document.getElementById('url-villages').textContent = USE_STATIC_API ? (base + '/api/villages/110101.json') : (API_BASE + '/village?districtCode=110101&limit=5'); |
| 1472 | + if (document.getElementById('url-search')) document.getElementById('url-search').textContent = USE_STATIC_API ? (base + ' (search not available on static)') : (API_BASE + '/search?q=jakarta'); |
| 1473 | + |
| 1474 | + // Search tab: disable on static API (GitHub Pages) |
| 1475 | + const searchRunBtn = document.getElementById('search-run-btn'); |
| 1476 | + const searchInput = document.getElementById('search-q'); |
| 1477 | + const searchNote = document.getElementById('search-helper-note'); |
| 1478 | + if (USE_STATIC_API) { |
| 1479 | + if (searchRunBtn) searchRunBtn.disabled = true; |
| 1480 | + if (searchInput) searchInput.disabled = true; |
| 1481 | + if (searchNote) { |
| 1482 | + searchNote.innerHTML = 'Search is <strong>not available</strong> on GitHub Pages static API. Use the Vercel API for <code>/search</code>.'; |
| 1483 | + } |
| 1484 | + } else { |
| 1485 | + if (searchInput) { |
| 1486 | + searchInput.addEventListener('keydown', (e) => { |
| 1487 | + if (e.key === 'Enter') trySearch(); |
| 1488 | + }); |
| 1489 | + } |
| 1490 | + } |
1405 | 1491 |
|
1406 | 1492 | const provinceSelect = document.getElementById('demo-province'); |
1407 | 1493 | const regencySelect = document.getElementById('demo-regency'); |
@@ -1585,6 +1671,43 @@ <h2><i class="fas fa-coffee"></i> Support This Project</h2> |
1585 | 1671 | } |
1586 | 1672 | } |
1587 | 1673 |
|
| 1674 | + async function trySearch() { |
| 1675 | + const responseBlock = document.getElementById('response-block'); |
| 1676 | + const responseContent = document.getElementById('response-content'); |
| 1677 | + const loadingSpinner = document.getElementById('loading-search'); |
| 1678 | + const buttonText = document.getElementById('text-search'); |
| 1679 | + const input = document.getElementById('search-q'); |
| 1680 | + |
| 1681 | + if (USE_STATIC_API) { |
| 1682 | + responseContent.textContent = 'Search is not available on GitHub Pages static API.\n\nUse the Vercel API endpoint: /search?q=...'; |
| 1683 | + responseBlock.classList.add('show'); |
| 1684 | + return; |
| 1685 | + } |
| 1686 | + |
| 1687 | + const q = (input && input.value ? input.value : '').trim(); |
| 1688 | + if (!q) { |
| 1689 | + responseContent.textContent = 'Please enter a search term in q (e.g., "jakarta").'; |
| 1690 | + responseBlock.classList.add('show'); |
| 1691 | + return; |
| 1692 | + } |
| 1693 | + |
| 1694 | + if (loadingSpinner) loadingSpinner.style.display = 'inline-block'; |
| 1695 | + if (buttonText) buttonText.textContent = 'Loading...'; |
| 1696 | + responseContent.textContent = 'Fetching data...'; |
| 1697 | + responseBlock.classList.add('show'); |
| 1698 | + |
| 1699 | + try { |
| 1700 | + const response = await fetch(apiSearchUrl(q)); |
| 1701 | + const data = await response.json(); |
| 1702 | + responseContent.textContent = JSON.stringify(data, null, 2); |
| 1703 | + } catch (error) { |
| 1704 | + responseContent.textContent = 'Error: ' + error.message; |
| 1705 | + } finally { |
| 1706 | + if (loadingSpinner) loadingSpinner.style.display = 'none'; |
| 1707 | + if (buttonText) buttonText.textContent = 'Run Request'; |
| 1708 | + } |
| 1709 | + } |
| 1710 | + |
1588 | 1711 | function copyUrl(elementId) { |
1589 | 1712 | const url = document.getElementById(elementId).textContent; |
1590 | 1713 | navigator.clipboard.writeText(url).then(() => { |
|
0 commit comments