NASA Planet Explorer untuk Blogger: Widget Gambar Planet Terbaru dari NASA

NASA Planet Explorer adalah widget Blogger yang menampilkan gambar planet, Matahari, Bulan, asteroid, komet, galaksi, pesawat antariksa, dan objek luar angkasa lain dari NASA Image and Video Library. Widget ini dibuat dengan HTML, CSS, dan native JavaScript sehingga dapat dipasang langsung pada Blogger tanpa jQuery, tanpa Worker, dan tanpa proxy tambahan.
Data gambar diambil langsung dari endpoint pencarian NASA Images API. Pengunjung dapat memilih kategori seperti Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune, Dwarf Planets, Asteroids & Comets, Universe, Spacecraft, Moon, hingga Exoplanets. Setiap kategori memakai satu feed engine yang sama, lalu hasilnya difilter, diurutkan berdasarkan tanggal, dan dibersihkan dari duplikat berdasarkan nasa_id.
Apa Itu NASA Planet Explorer?
NASA Planet Explorer dibuat untuk menampilkan koleksi gambar NASA dalam bentuk widget visual yang lebih nyaman dibanding membuka arsip gambar satu per satu. Ketika sebuah kategori dipilih, engine akan mengambil data dari NASA Images API kemudian mengubahnya menjadi slideshow, thumbnail, metadata, serta link menuju halaman sumber NASA.
Konsepnya mirip widget data real-time yang sebelumnya pernah dibahas pada artikel Widget Gempa BMKG untuk Blogger dengan Data JSON Real-Time. Bedanya, widget ini memanfaatkan katalog gambar NASA dan membaginya berdasarkan objek tata surya maupun kategori astronomi.

Fitur NASA Planet Explorer
Kategori Gambar yang Tersedia
Versi widget ini menyediakan kategori Latest, Sun, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune, Moon, Dwarf Planets, Asteroids & Comets, Universe, Spacecraft, dan Exoplanets.
Untuk pembaca yang ingin memahami perbedaan istilah astronomi yang sering muncul pada kategori tersebut, CodeFlare juga mempunyai artikel perbedaan asteroid, komet, dan meteor.
Live Preview NASA Planet Explorer
Di bagian berikut nantinya pengunjung dapat mencoba widget secara langsung. Pilih planet atau kategori lain, gunakan tombol previous/next, klik thumbnail, atau buka tombol Detail untuk melihat metadata gambar.
Cara Pasang NASA Planet Explorer di Blogger
Widget dapat dipasang melalui gadget HTML/JavaScript, di dalam halaman statis, atau pada area HTML artikel jika template mengizinkannya. Untuk pemasangan melalui Tata Letak Blogger, lakukan langkah berikut.
- 1Buka Blogger
Masuk ke Dashboard Blogger lalu pilih blog yang akan dipasangi widget.
- 2Buka Tata Letak
Pilih lokasi widget, kemudian klik Tambahkan Gadget.
- 3Pilih HTML/JavaScript
Buka gadget HTML/JavaScript agar kode dapat ditempel langsung.
- 4Copy Kode Widget
Salin seluruh kode pada bagian Kode Lengkap di bawah.
- 5Simpan
Simpan gadget, kemudian buka blog untuk memastikan gambar NASA berhasil dimuat.
Kode Lengkap NASA Planet Explorer
Salin seluruh HTML, CSS, dan JavaScript widget tanpa memotong bagian engine. Kode final sebaiknya ditempatkan dalam satu gadget HTML/JavaScript supaya CSS dan JavaScript ikut dimuat bersama widget.
<div class="cfNASA-shell">
<header class="cfNASA-head">
<div class="cfNASA-brand">
<span class="cfNASA-brandIcon"><i class="fa-solid fa-shuttle-space"></i></span>
<div class="cfNASA-brandText">
<b>NASA PLANET <em>EXPLORER</em></b>
<small>Latest images from NASA Image Library</small>
</div>
</div>
<div class="cfNASA-status">
<span class="cfNASA-statusDot"></span>
<div>
<b>NASA FEED ONLINE</b>
<small data-status>Connecting...</small>
</div>
</div>
<button class="cfNASA-menuBtn" type="button" aria-label="Open NASA feeds">
<i class="fa-solid fa-bars"></i>
</button>
</header>
<nav class="cfNASA-tabs" aria-label="NASA image categories"></nav>
<section class="cfNASA-stage">
<div class="cfNASA-loading">
<span class="cfNASA-spinner"></span>
<b>Loading NASA imagery...</b>
<small>NASA Image and Video Library</small>
</div>
<div class="cfNASA-hero" hidden>
<img class="cfNASA-heroImg" alt="" decoding="async"/>
<div class="cfNASA-overlay"></div>
<button class="cfNASA-navBtn cfNASA-prev" type="button" aria-label="Previous image">
<i class="fa-solid fa-chevron-left"></i>
</button>
<button class="cfNASA-navBtn cfNASA-next" type="button" aria-label="Next image">
<i class="fa-solid fa-chevron-right"></i>
</button>
<div class="cfNASA-content">
<span class="cfNASA-kicker">LATEST NASA IMAGE</span>
<h2 class="cfNASA-title"></h2>
<p class="cfNASA-desc"></p>
<div class="cfNASA-meta">
<span><i class="fa-regular fa-calendar"></i><b data-date>—</b></span>
<span><i class="fa-solid fa-building"></i><b data-center>NASA</b></span>
<span><i class="fa-solid fa-hashtag"></i><b data-nasaid>—</b></span>
</div>
<div class="cfNASA-actions">
<button class="cfNASA-detailBtn" type="button">
<i class="fa-solid fa-circle-info"></i> Detail
</button>
<a class="cfNASA-sourceBtn" href="#" target="_blank" rel="noopener nofollow">
<i class="fa-solid fa-arrow-up-right-from-square"></i> NASA Source
</a>
</div>
</div>
<div class="cfNASA-counter">
<b data-current>01</b><span>/</span><span data-total>00</span>
</div>
</div>
</section>
<div class="cfNASA-thumbs"></div>
<footer class="cfNASA-foot">
<span><i class="fa-solid fa-satellite-dish"></i> NASA Image Library</span>
<span data-active-feed>Latest</span>
</footer>
</div>
<div class="cfNASA-feedPanel" aria-hidden="true">
<div class="cfNASA-panelCard">
<div class="cfNASA-panelHead">
<div>
<b>ALL NASA FEEDS</b>
<small>Select image category</small>
</div>
<button class="cfNASA-closePanel" type="button" aria-label="Close">
<i class="fa-solid fa-xmark"></i>
</button>
</div>
<div class="cfNASA-feedList"></div>
</div>
</div>
<div class="cfNASA-modal" aria-hidden="true">
<div class="cfNASA-modalCard">
<button class="cfNASA-modalClose" type="button" aria-label="Close">
<i class="fa-solid fa-xmark"></i>
</button>
<div class="cfNASA-modalImage"><img alt="" decoding="async"/></div>
<div class="cfNASA-modalBody">
<span class="cfNASA-modalLabel">NASA IMAGE LIBRARY</span>
<h3></h3>
<p class="cfNASA-modalDesc"></p>
<div class="cfNASA-modalMeta"></div>
<a class="cfNASA-modalLink" href="#" target="_blank" rel="noopener nofollow">
View Original on NASA
<i class="fa-solid fa-arrow-up-right-from-square"></i>
</a>
</div>
</div>
</div>
</div>
<style>
.cfNASAExplorer{--cfNASA-panel:#0a1727;--cfNASA-panel2:#0d1e33;--cfNASA-line:#173a5d;--cfNASA-blue:#1f9dff;--cfNASA-cyan:#26ddff;--cfNASA-green:#21dc83;--cfNASA-text:#edf7ff;--cfNASA-muted:#8faac0;--cfNASA-radius:16px;position:relative;width:100%;font:15px/1.5 Roboto,Arial,sans-serif}
.cfNASAExplorer *{box-sizing:border-box}
.cfNASA-shell{position:relative;overflow:hidden;width:100%;border:1px solid rgba(54,162,240,.45);border-radius:var(--cfNASA-radius);background:radial-gradient(circle at 78% -10%,rgba(38,130,255,.21),transparent 35%),radial-gradient(circle at 15% 100%,rgba(40,219,255,.08),transparent 28%),linear-gradient(145deg,#071421,#030a13);box-shadow:0 18px 48px rgba(0,0,0,.25)}
.cfNASA-head{min-height:78px;padding:13px 15px;display:flex;align-items:center;gap:13px;border-bottom:1px solid rgba(86,166,225,.18)}
.cfNASA-brand{min-width:0;flex:1;display:flex;align-items:center;gap:11px}
.cfNASA-brandIcon{flex:0 0 46px;width:46px;height:46px;display:grid;place-items:center;border-radius:50%;color:#fff;font-size:20px;background:radial-gradient(circle at 35% 30%,#32bdff,#0b3b84 68%);border:1px solid rgba(99,210,255,.7);box-shadow:0 0 20px rgba(25,161,255,.24)}
.cfNASA-brandText{min-width:0}
.cfNASA-brandText b{display:block;color:var(--cfNASA-text);font-size:20px;line-height:1.15;letter-spacing:.25px}
.cfNASA-brandText em{color:var(--cfNASA-cyan);font-style:normal}
.cfNASA-brandText small{display:block;margin-top:4px;color:var(--cfNASA-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cfNASA-status{display:flex;align-items:center;gap:8px}
.cfNASA-statusDot{width:9px;height:9px;border-radius:50%;background:var(--cfNASA-green);box-shadow:0 0 12px var(--cfNASA-green)}
.cfNASA-status b{display:block;color:var(--cfNASA-green);font-size:12px}
.cfNASA-status small{display:block;margin-top:2px;color:var(--cfNASA-muted);font-size:11px}
.cfNASA-menuBtn{display:none;width:40px;height:40px;border:1px solid var(--cfNASA-line);border-radius:9px;background:var(--cfNASA-panel2);color:var(--cfNASA-cyan);cursor:pointer}
.cfNASA-tabs{display:flex;align-items:stretch;overflow-x:auto;gap:4px;padding:7px;scrollbar-width:none;background:rgba(2,9,17,.75);border-bottom:1px solid rgba(73,150,205,.16)}
.cfNASA-tabs::-webkit-scrollbar{display:none}
.cfNASA-tab{flex:1 0 72px;min-width:72px;height:68px;padding:5px;border:1px solid transparent;border-radius:10px;background:transparent;color:#9db4c8;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;transition:.2s ease}
.cfNASA-tab i{font-size:18px}
.cfNASA-tab span{font-size:10px;white-space:nowrap}
.cfNASA-tab:hover{color:#fff;background:rgba(23,105,170,.13)}
.cfNASA-tab.is-active{color:#fff;background:linear-gradient(180deg,rgba(24,147,255,.26),rgba(13,78,131,.13));border-color:var(--cfNASA-blue);box-shadow:inset 0 0 18px rgba(22,144,255,.15),0 0 13px rgba(0,151,255,.14)}
.cfNASA-tab.is-active i{color:var(--cfNASA-cyan)}
.cfNASA-stage{position:relative;padding:9px;min-height:430px}
.cfNASA-loading{position:absolute;inset:9px;z-index:20;min-height:410px;border-radius:13px;display:flex;flex-direction:column;align-items:center;justify-content:center;background:radial-gradient(circle at center,rgba(23,114,175,.17),transparent 43%),#06101b;color:#fff}
.cfNASA-loading[hidden]{display:none}
.cfNASA-loading small{margin-top:5px;color:var(--cfNASA-muted)}
.cfNASA-spinner{width:38px;height:38px;margin-bottom:12px;border-radius:50%;border:3px solid rgba(76,179,255,.16);border-top-color:var(--cfNASA-cyan);animation:cfNASAspin .8s linear infinite}
@keyframes cfNASAspin{to{transform:rotate(360deg)}}
.cfNASA-hero{position:relative;overflow:hidden;height:410px;border-radius:13px;border:1px solid rgba(66,164,235,.31);background:#02070c}
.cfNASA-hero[hidden]{display:none}
.cfNASA-heroImg{display:block;width:100%;height:100%;object-fit:cover;transition:opacity .22s ease,transform .5s ease}
.cfNASA-hero:hover .cfNASA-heroImg{transform:scale(1.015)}
.cfNASA-overlay{position:absolute;inset:0;pointer-events:none;background:linear-gradient(90deg,rgba(1,8,15,.96) 0%,rgba(2,10,18,.75) 31%,rgba(2,9,16,.18) 64%,rgba(0,0,0,.3) 100%),linear-gradient(0deg,rgba(0,0,0,.48),transparent 47%)}
.cfNASA-content{position:absolute;z-index:3;left:6%;top:50%;width:min(440px,48%);transform:translateY(-50%);color:var(--cfNASA-text)}
.cfNASA-kicker{display:block;margin-bottom:8px;color:var(--cfNASA-cyan);font-size:12px;font-weight:700;letter-spacing:.75px}
.cfNASA-title{margin:0 0 10px;padding:0;color:#fff;font-size:30px;line-height:1.12}
.cfNASA-desc{margin:0 0 13px;color:#d2e3ef;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}
.cfNASA-meta{display:flex;flex-wrap:wrap;gap:9px 14px;margin-bottom:14px}
.cfNASA-meta span{display:flex;align-items:center;gap:6px;color:#a8c2d6;font-size:11px}
.cfNASA-meta i{color:var(--cfNASA-cyan)}
.cfNASA-actions{display:flex;flex-wrap:wrap;gap:8px}
.cfNASA-detailBtn,.cfNASA-sourceBtn{min-height:40px;padding:0 14px;border-radius:9px;display:inline-flex;align-items:center;justify-content:center;gap:7px;text-decoration:none;font:600 12px Roboto,Arial,sans-serif}
.cfNASA-detailBtn{border:1px solid var(--cfNASA-blue);color:#fff;background:linear-gradient(135deg,#007ff1,#0757b3);cursor:pointer}
.cfNASA-sourceBtn{border:1px solid rgba(100,183,241,.34);color:#eaf7ff;background:rgba(6,25,42,.67)}
.cfNASA-navBtn{position:absolute;z-index:5;top:50%;transform:translateY(-50%);width:44px;height:44px;border:1px solid rgba(155,220,255,.72);border-radius:50%;background:rgba(4,17,30,.66);color:#fff;cursor:pointer;backdrop-filter:blur(7px)}
.cfNASA-navBtn:hover{background:#0879d1}
.cfNASA-prev{left:13px}.cfNASA-next{right:13px}
.cfNASA-counter{position:absolute;z-index:4;right:17px;bottom:15px;display:flex;gap:4px;align-items:baseline;padding:5px 9px;border-radius:7px;background:rgba(0,0,0,.58);color:#b7ccdd;font-size:11px;backdrop-filter:blur(5px)}
.cfNASA-counter b{color:var(--cfNASA-cyan);font-size:15px}
.cfNASA-thumbs{display:flex;gap:8px;overflow-x:auto;padding:0 9px 10px;scrollbar-width:thin}
.cfNASA-thumb{flex:0 0 124px;width:124px;padding:4px;border:1px solid #173952;border-radius:9px;background:#071420;color:#d9e9f5;cursor:pointer}
.cfNASA-thumb.is-active{border-color:var(--cfNASA-cyan);box-shadow:0 0 12px rgba(36,225,255,.18)}
.cfNASA-thumb img{width:100%;height:72px;object-fit:cover;display:block;border-radius:6px;background:#07111c}
.cfNASA-thumb span{display:block;padding:5px 3px 2px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:10px}
.cfNASA-foot{min-height:40px;padding:8px 11px;display:flex;align-items:center;justify-content:space-between;gap:10px;border-top:1px solid rgba(60,141,201,.18);color:var(--cfNASA-muted);font-size:10px}
.cfNASA-foot span{display:flex;align-items:center;gap:6px}
.cfNASA-foot i{color:var(--cfNASA-cyan)}
.cfNASA-feedPanel,.cfNASA-modal{position:fixed;inset:0;z-index:99999;display:none;align-items:center;justify-content:center;padding:17px;background:rgba(0,5,10,.77);backdrop-filter:blur(8px)}
.cfNASA-feedPanel.is-open,.cfNASA-modal.is-open{display:flex}
.cfNASA-panelCard{width:min(540px,100%);max-height:min(680px,90vh);overflow:hidden;border:1px solid #23567b;border-radius:15px;background:#081421;box-shadow:0 30px 80px rgba(0,0,0,.55)}
.cfNASA-panelHead{display:flex;align-items:center;justify-content:space-between;padding:14px;border-bottom:1px solid #173650;color:#fff}
.cfNASA-panelHead b,.cfNASA-panelHead small{display:block}
.cfNASA-panelHead small{margin-top:2px;color:var(--cfNASA-muted)}
.cfNASA-closePanel,.cfNASA-modalClose{width:38px;height:38px;border:0;border-radius:50%;background:#14293b;color:#fff;cursor:pointer}
.cfNASA-feedList{max-height:570px;overflow:auto;padding:9px}
.cfNASA-feedItem{width:100%;min-height:50px;padding:9px 11px;display:flex;align-items:center;gap:10px;border:1px solid transparent;border-radius:9px;background:transparent;color:#d9e9f4;cursor:pointer;text-align:left}
.cfNASA-feedItem:hover,.cfNASA-feedItem.is-active{border-color:#245b84;background:#0d2235}
.cfNASA-feedItem i{width:25px;text-align:center;color:var(--cfNASA-cyan)}
.cfNASA-modalCard{position:relative;width:min(720px,100%);max-height:90vh;overflow:auto;border:1px solid #20557d;border-radius:15px;background:#071421;box-shadow:0 30px 80px rgba(0,0,0,.6)}
.cfNASA-modalClose{position:absolute;z-index:3;top:10px;right:10px}
.cfNASA-modalImage{aspect-ratio:16/9;overflow:hidden;background:#02070c}
.cfNASA-modalImage img{width:100%;height:100%;object-fit:cover}
.cfNASA-modalBody{padding:17px;color:#cfe0ec}
.cfNASA-modalLabel{font-size:10px;font-weight:700;color:var(--cfNASA-cyan)}
.cfNASA-modalBody h3{margin:7px 0 10px;color:#fff;font-size:23px;line-height:1.25}
.cfNASA-modalDesc{margin:0 0 14px}
.cfNASA-modalMeta{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:7px;margin-bottom:13px;padding:11px;border-radius:9px;background:#0c1d2c;font-size:11px}
.cfNASA-modalLink{min-height:40px;padding:0 14px;display:inline-flex;align-items:center;gap:7px;border-radius:8px;color:#fff;background:#087ae0;text-decoration:none;font-weight:600}
@media(max-width:800px){
.cfNASA-status{display:none}
.cfNASA-menuBtn{display:block}
.cfNASA-brandText b{font-size:17px}
.cfNASA-stage{min-height:390px}
.cfNASA-hero{height:370px}
.cfNASA-content{width:67%}
.cfNASA-title{font-size:24px}
}
@media(max-width:600px){
.cfNASA-shell{border-radius:13px}
.cfNASA-head{min-height:60px;padding:9px}
.cfNASA-brandIcon{width:38px;height:38px;flex-basis:38px;font-size:16px}
.cfNASA-brandText b{font-size:14px}
.cfNASA-brandText small{font-size:9px}
.cfNASA-tabs{padding:5px}
.cfNASA-tab{flex-basis:60px;min-width:60px;height:56px}
.cfNASA-tab i{font-size:15px}
.cfNASA-tab span{font-size:8px}
.cfNASA-stage{padding:6px;min-height:425px}
.cfNASA-loading{inset:6px;min-height:413px}
.cfNASA-hero{height:413px}
.cfNASA-heroImg{height:56%;object-position:center}
.cfNASA-overlay{background:linear-gradient(0deg,rgba(1,7,13,.98) 0%,rgba(1,9,16,.84) 39%,rgba(1,7,13,.08) 73%)}
.cfNASA-content{top:auto;left:15px;right:15px;bottom:16px;width:auto;transform:none}
.cfNASA-kicker{font-size:9px}
.cfNASA-title{font-size:21px;margin-bottom:7px}
.cfNASA-desc{font-size:11px;-webkit-line-clamp:2}
.cfNASA-meta{margin-bottom:10px}
.cfNASA-meta span{font-size:9px}
.cfNASA-actions{padding-right:54px}
.cfNASA-detailBtn,.cfNASA-sourceBtn{min-height:35px;padding:0 10px;font-size:10px}
.cfNASA-navBtn{width:36px;height:36px;top:27%}
.cfNASA-prev{left:10px}.cfNASA-next{right:10px}
.cfNASA-counter{right:11px;bottom:14px}
.cfNASA-thumb{flex-basis:101px;width:101px}
.cfNASA-thumb img{height:60px}
.cfNASA-foot{font-size:9px}
.cfNASA-modalMeta{grid-template-columns:1fr}
}
@media(prefers-color-scheme:light){
.cfNASAExplorer{--cfNASA-text:#12283a;--cfNASA-muted:#617e93}
.cfNASA-shell{background:radial-gradient(circle at 80% -10%,rgba(26,131,255,.11),transparent 35%),#f7fbfe}
.cfNASA-head,.cfNASA-foot{background:#fff}
.cfNASA-brandText b{color:#12283a}
.cfNASA-tabs{background:#eef7fc}
.cfNASA-tab{color:#587186}
.cfNASA-tab:hover,.cfNASA-tab.is-active{color:#12324a}
}
</style>
<script>
(()=>{
"use strict";
const API="https://images-api.nasa.gov/search";
const MAX_ITEMS=18;
const THUMB_ITEMS=10;
const GLOBAL_CACHE=window.__cfNASAFeedCache||(window.__cfNASAFeedCache=new Map());
const FEEDS={
latest:{label:"Latest",icon:"fa-house",q:"solar system planet"},
sun:{label:"Sun",icon:"fa-sun",q:"sun solar"},
mercury:{label:"Mercury",icon:"fa-circle",q:"Mercury planet"},
venus:{label:"Venus",icon:"fa-circle",q:"Venus planet"},
earth:{label:"Earth",icon:"fa-earth-americas",q:"Earth planet"},
mars:{label:"Mars",icon:"fa-circle",q:"Mars planet"},
jupiter:{label:"Jupiter",icon:"fa-circle",q:"Jupiter planet"},
saturn:{label:"Saturn",icon:"fa-circle",q:"Saturn planet"},
uranus:{label:"Uranus",icon:"fa-circle",q:"Uranus planet"},
neptune:{label:"Neptune",icon:"fa-circle",q:"Neptune planet"},
moon:{label:"Moon",icon:"fa-moon",q:"Moon lunar"},
dwarf:{label:"Dwarf Planets",icon:"fa-circle-dot",q:"Pluto dwarf planet"},
asteroid:{label:"Asteroids & Comets",icon:"fa-meteor",q:"asteroid comet"},
universe:{label:"Universe",icon:"fa-star",q:"galaxy nebula universe"},
spacecraft:{label:"Spacecraft",icon:"fa-satellite",q:"spacecraft mission"},
exoplanet:{label:"Exoplanets",icon:"fa-earth-europe",q:"exoplanet"}
};
function init(root){
if(root.dataset.ready==="1")return;
root.dataset.ready="1";
root.tabIndex=0;
const tabs=root.querySelector(".cfNASA-tabs"),
loading=root.querySelector(".cfNASA-loading"),
hero=root.querySelector(".cfNASA-hero"),
heroImg=root.querySelector(".cfNASA-heroImg"),
title=root.querySelector(".cfNASA-title"),
desc=root.querySelector(".cfNASA-desc"),
thumbs=root.querySelector(".cfNASA-thumbs"),
feedList=root.querySelector(".cfNASA-feedList"),
panel=root.querySelector(".cfNASA-feedPanel"),
modal=root.querySelector(".cfNASA-modal"),
statusEl=root.querySelector("[data-status]"),
dateEl=root.querySelector("[data-date]"),
centerEl=root.querySelector("[data-center]"),
nasaIdEl=root.querySelector("[data-nasaid]"),
currentEl=root.querySelector("[data-current]"),
totalEl=root.querySelector("[data-total]"),
activeFeedEl=root.querySelector("[data-active-feed]"),
sourceBtn=root.querySelector(".cfNASA-sourceBtn");
let active="latest",items=[],index=0,touchStartX=0,controller=null,requestId=0;
const esc=s=>String(s??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");
const detailURL=id=>"https://images.nasa.gov/details/"+encodeURIComponent(id||"");
function cleanText(v){
if(!v)return"";
const d=document.createElement("div");
d.innerHTML=v;
return(d.textContent||"").replace(/\s+/g," ").trim()
}
function formatDate(v){
if(!v)return"NASA Archive";
const d=new Date(v);
if(Number.isNaN(d.getTime()))return"NASA Archive";
return new Intl.DateTimeFormat("en",{year:"numeric",month:"short",day:"numeric"}).format(d)
}
function buildMenus(){
const keys=Object.keys(FEEDS),main=keys.slice(0,10);
tabs.innerHTML=main.map(id=>{
const f=FEEDS[id];
return'<button type="button" class="cfNASA-tab'+(id===active?' is-active':'')+'" data-feed="'+id+'"><i class="fa-solid '+f.icon+'"></i><span>'+esc(f.label)+'</span></button>'
}).join("")+'<button type="button" class="cfNASA-tab" data-more="1"><i class="fa-solid fa-ellipsis"></i><span>More</span></button>';
feedList.innerHTML=keys.map(id=>{
const f=FEEDS[id];
return'<button type="button" class="cfNASA-feedItem'+(id===active?' is-active':'')+'" data-feed="'+id+'"><i class="fa-solid '+f.icon+'"></i><span>'+esc(f.label)+'</span></button>'
}).join("")
}
async function getFeed(id){
if(GLOBAL_CACHE.has(id))return GLOBAL_CACHE.get(id);
const feed=FEEDS[id]||FEEDS.latest;
if(controller)controller.abort();
controller=new AbortController();
const url=API+"?media_type=image&q="+encodeURIComponent(feed.q);
const res=await fetch(url,{signal:controller.signal,cache:"no-store"});
if(!res.ok)throw new Error("NASA API "+res.status);
const json=await res.json(),raw=json?.collection?.items||[],seen=new Set();
const mapped=raw.map(item=>{
const d=item?.data?.[0]||{},l=item?.links?.find(x=>x?.render==="image")||item?.links?.[0]||{};
return{
id:d.nasa_id||"",
title:d.title||"NASA Image",
desc:cleanText(d.description||d.description_508||""),
date:d.date_created||"",
center:d.center||"NASA",
photographer:d.photographer||"",
keywords:Array.isArray(d.keywords)?d.keywords:[],
image:l.href||"",
mediaType:d.media_type||"image"
}
}).filter(x=>{
if(!x.image||!x.id||seen.has(x.id))return false;
seen.add(x.id);return true
}).sort((a,b)=>{
const da=new Date(a.date).getTime()||0,db=new Date(b.date).getTime()||0;
return db-da
}).slice(0,MAX_ITEMS);
GLOBAL_CACHE.set(id,mapped);
return mapped
}
function fallback(){
return[{id:"PIA02873",title:"NASA Planet Explorer",desc:"NASA imagery is temporarily unavailable. Please try again later.",date:"",center:"NASA",photographer:"",keywords:[],image:"https://images-assets.nasa.gov/image/PIA02873/PIA02873~orig.jpg"}]
}
function preloadNext(){
if(items.length<2)return;
const next=items[(index+1)%items.length];
if(next?.image){const i=new Image();i.src=next.image}
}
function render(){
if(!items.length)return;
index=(index+items.length)%items.length;
const item=items[index];
heroImg.style.opacity="0";
const img=new Image();
img.onload=()=>{
heroImg.src=item.image;
heroImg.alt=item.title;
heroImg.style.opacity="1"
};
img.onerror=()=>{
heroImg.src="https://images-assets.nasa.gov/image/PIA02873/PIA02873~orig.jpg";
heroImg.alt="NASA Planet Explorer";
heroImg.style.opacity="1"
};
img.src=item.image;
title.textContent=item.title;
desc.textContent=item.desc||"NASA image from the NASA Image and Video Library.";
dateEl.textContent=formatDate(item.date);
centerEl.textContent=item.center||"NASA";
nasaIdEl.textContent=item.id||"NASA";
sourceBtn.href=detailURL(item.id);
currentEl.textContent=String(index+1).padStart(2,"0");
totalEl.textContent=String(items.length).padStart(2,"0");
thumbs.innerHTML=items.slice(0,THUMB_ITEMS).map((x,i)=>
'<button type="button" class="cfNASA-thumb'+(i===index?' is-active':'')+'" data-index="'+i+'" title="'+esc(x.title)+'"><img src="'+esc(x.image)+'" alt="'+esc(x.title)+'" loading="lazy" decoding="async"/><span>'+esc(x.title)+'</span></button>'
).join("");
preloadNext()
}
async function load(id){
if(!FEEDS[id])return;
const thisRequest=++requestId;
active=id;index=0;
loading.hidden=false;
hero.hidden=true;
thumbs.innerHTML="";
buildMenus();
activeFeedEl.textContent=FEEDS[id].label;
statusEl.textContent="Loading "+FEEDS[id].label+"...";
try{
const result=await getFeed(id);
if(thisRequest!==requestId)return;
items=result;
if(!items.length)throw new Error("No NASA results");
statusEl.textContent="Updated "+new Intl.DateTimeFormat("en",{hour:"2-digit",minute:"2-digit"}).format(new Date())
}catch(err){
if(err?.name==="AbortError")return;
if(thisRequest!==requestId)return;
console.info("[CodeFlare NASA Feed]",err.message||err);
items=fallback();
statusEl.textContent="NASA feed temporarily unavailable"
}
loading.hidden=true;
hero.hidden=false;
render()
}
function move(step){
if(!items.length)return;
index=(index+step+items.length)%items.length;
render()
}
function openPanel(){
panel.classList.add("is-open");
panel.setAttribute("aria-hidden","false")
}
function closePanel(){
panel.classList.remove("is-open");
panel.setAttribute("aria-hidden","true")
}
function openModal(){
const item=items[index];
if(!item)return;
const mimg=modal.querySelector(".cfNASA-modalImage img");
mimg.src=item.image;
mimg.alt=item.title;
modal.querySelector("h3").textContent=item.title;
modal.querySelector(".cfNASA-modalDesc").textContent=item.desc||"No description available.";
modal.querySelector(".cfNASA-modalMeta").innerHTML=
'<span><b>Date</b><br>'+esc(formatDate(item.date))+'</span>'+
'<span><b>NASA ID</b><br>'+esc(item.id||"—")+'</span>'+
'<span><b>Center</b><br>'+esc(item.center||"NASA")+'</span>'+
'<span><b>Photographer</b><br>'+esc(item.photographer||"Not listed")+'</span>';
modal.querySelector(".cfNASA-modalLink").href=detailURL(item.id);
modal.classList.add("is-open");
modal.setAttribute("aria-hidden","false")
}
function closeModal(){
modal.classList.remove("is-open");
modal.setAttribute("aria-hidden","true")
}
root.addEventListener("click",e=>{
const tab=e.target.closest(".cfNASA-tab");
if(tab){
if(tab.dataset.more){openPanel();return}
load(tab.dataset.feed);return
}
const feed=e.target.closest(".cfNASA-feedItem");
if(feed){closePanel();load(feed.dataset.feed);return}
const thumb=e.target.closest(".cfNASA-thumb");
if(thumb){index=Number(thumb.dataset.index)||0;render();return}
if(e.target.closest(".cfNASA-prev"))move(-1);
if(e.target.closest(".cfNASA-next"))move(1);
if(e.target.closest(".cfNASA-menuBtn"))openPanel();
if(e.target.closest(".cfNASA-closePanel"))closePanel();
if(e.target.closest(".cfNASA-detailBtn"))openModal();
if(e.target.closest(".cfNASA-modalClose"))closeModal();
if(e.target===panel)closePanel();
if(e.target===modal)closeModal()
});
hero.addEventListener("touchstart",e=>{
touchStartX=e.changedTouches[0].clientX
},{passive:true});
hero.addEventListener("touchend",e=>{
const diff=e.changedTouches[0].clientX-touchStartX;
if(Math.abs(diff)>45)move(diff>0?-1:1)
},{passive:true});
root.addEventListener("keydown",e=>{
if(e.key==="ArrowLeft"){e.preventDefault();move(-1)}
if(e.key==="ArrowRight"){e.preventDefault();move(1)}
if(e.key==="Escape"){closePanel();closeModal()}
});
buildMenus();
load("latest")
}
document.querySelectorAll("[data-cf-nasa]").forEach(init)
})();
</script>
Bagaimana Feed Engine Widget Bekerja?
Engine mempunyai daftar kategori seperti mars, jupiter, saturn, dan kategori lainnya. Masing-masing kategori hanya menyimpan nama, ikon, serta kata kunci pencarian. Saat pengunjung memilih tab, JavaScript membangun request ke endpoint https://images-api.nasa.gov/search dengan parameter media_type=image dan kata kunci kategori.
Hasil dari API kemudian diproses menjadi data yang dibutuhkan widget: NASA ID, judul, deskripsi, tanggal, NASA center, photographer, dan URL gambar. Data yang tidak mempunyai gambar atau NASA ID akan dilewati. Item dengan NASA ID yang sama juga tidak akan ditampilkan dua kali.
Kenapa Tidak Menggunakan Worker atau Proxy?
NASA Image and Video Library menyediakan endpoint JSON yang dapat dibaca langsung dari JavaScript. Karena itu widget tidak perlu mengubah RSS XML menjadi JSON melalui proxy dan tidak membutuhkan Worker hanya untuk menampilkan gambar. Pendekatan ini membuat kode lebih sederhana dan mengurangi ketergantungan pada layanan tambahan.
Konsep penggunaan feed sebagai sumber widget juga pernah dibahas dalam daftar RSS feed dan cara mengecek feed serta tutorial membuat RSS Feed Widget Berita di Blogger. NASA Planet Explorer berbeda karena sumber utamanya sudah berupa JSON API.
Cache dan Filter Duplikat
Widget membuat cache dengan Map(). Setelah kategori seperti Jupiter berhasil dimuat, data tersebut disimpan selama halaman masih terbuka. Jika pengunjung berpindah ke Mars kemudian kembali ke Jupiter, engine dapat menggunakan data yang sudah ada tanpa melakukan request yang sama berulang kali.
Filter duplikat memakai nasa_id. Teknik ini penting karena sebuah pencarian kadang dapat mengembalikan beberapa item yang merujuk pada aset NASA yang sama.
Responsive untuk Desktop dan Mobile
Pada desktop, gambar hero memenuhi area utama sementara judul, deskripsi, metadata, dan tombol ditampilkan di sisi gambar. Pada layar kecil, gambar dipindahkan ke bagian atas dan informasi berada di bawahnya agar teks tidak menutupi objek utama terlalu banyak.
Thumbnail menggunakan horizontal scrolling sehingga jumlah gambar tidak membuat widget melebar keluar layar. Swipe juga tersedia pada perangkat sentuh, sedangkan pengguna desktop dapat memakai tombol previous/next atau tombol panah keyboard.
NASA Images API dan Hak Penggunaan Gambar
Widget hanya menampilkan data dari NASA Image and Video Library dan menyediakan link kembali ke halaman detail NASA. Setiap aset dapat mempunyai metadata, kredit, atau ketentuan tambahan masing-masing. Karena itu, jika sebuah gambar akan digunakan kembali di luar tampilan widget, periksa halaman sumber dan kredit yang tercantum pada aset tersebut.
Widget Lain yang Bisa Dipasang di Blogger
NASA Planet Explorer dapat dipasang bersama widget informatif lain selama halaman tidak memuat terlalu banyak request eksternal sekaligus. Untuk melihat pilihan lainnya, buka kumpulan widget Blogger responsive dan native JavaScript.
Jika ingin membuat halaman informasi yang selalu berubah mengikuti sumber data, prinsip yang digunakan widget NASA ini juga dapat diterapkan pada feed berita, data cuaca, statistik, atau API publik lainnya: ambil data, normalisasi, cache, filter, lalu render hanya elemen yang dibutuhkan.
Pertanyaan yang Sering Ditanyakan
Apakah NASA Planet Explorer membutuhkan API key?
Widget versi ini menggunakan NASA Image and Video Library Search API yang dapat diakses langsung oleh frontend tanpa memasukkan API key ke dalam kode widget.
Apakah widget membutuhkan jQuery?
Tidak. Seluruh navigasi, fetch data, modal, swipe, cache, dan rendering menggunakan native JavaScript.
Apakah harus menggunakan Cloudflare Worker?
Tidak. Versi ini mengambil JSON langsung dari NASA Images API.
Apakah bisa dipasang lebih dari satu kali?
Ya. Inisialisasi menggunakan atribut data-cf-nasa dan setiap instance mempunyai state tampilan sendiri, sedangkan cache data dapat dipakai bersama.
Kenapa gambar pada suatu kategori kadang tidak persis berupa planet?
NASA Images API menggunakan pencarian metadata. Kata kunci seperti Earth atau Mars dapat menemukan gambar misi, spacecraft, permukaan, atau objek terkait. Query kategori dapat diperketat jika diperlukan.
Apakah widget cocok untuk sidebar?
Bisa, tetapi desain hero lebih nyaman pada area artikel atau kolom yang cukup lebar. Untuk sidebar sempit, ukuran hero dan metadata sebaiknya disederhanakan.
NASA Planet Explorer memberi cara yang lebih visual untuk menampilkan koleksi gambar NASA langsung di Blogger. Satu feed engine menangani banyak kategori, sementara cache, filter duplikat, lazy loading, preload, dan layout responsif menjaga widget tetap praktis digunakan.
Karena sumber data berasal dari NASA Image and Video Library, isi widget dapat berubah mengikuti koleksi yang tersedia. Setelah kode dipasang, pengunjung dapat langsung berpindah antarplanet, membuka detail gambar, dan menjelajahi sumber NASA tanpa perlu memuat ulang halaman.
No comments
💬 Share Your Thoughts & Join the Hall of Fame!
Punya pendapat atau tips tentang artikel ini? Tuliskan komentar kamu sekarang! 🚀
💎 Komentar yang bermanfaat, relevan, dan positif berkesempatan tampil di CodeFlare Hall of Fame dan masuk ke Top Commentators Widget.
👉 Comment now. Share your ideas. Get noticed on codeflare.net