diff --git a/README.md b/README.md index 255ab44..194b8d4 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,36 @@ -# 🚀 Project: Complex NASA API - -### Goal: Use NASA's API to return all of their facility locations (~400). Display the name of the facility, its location, and the weather at the facility currently. - -### How to submit your code for review: - -- Fork and clone this repo -- Create a new branch called answer -- Checkout answer branch -- Push to your fork -- Issue a pull request -- Your pull request description should contain the following: - - (1 to 5 no 3) I completed the challenge - - (1 to 5 no 3) I feel good about my code - - Anything specific on which you want feedback! - -Example: -``` -I completed the challenge: 5 -I feel good about my code: 4 -I'm not sure if my constructors are setup cleanly... -``` +# 🌌 NASA Facilities + Current Weather + +An interactive display of all NASA facilities across the United States, paired with live current weather data for each location. +Built to explore large-scale public data handling and chained API requests, this project combines clean visuals with real-time information. + +[Live Demo](https://complex-nasa-api.vercel.app/) + +![screenshot](img/facility.png "NASA Facilities + Current Weather") + +--- + +## How It’s Made +**Tech used:** HTML, CSS, JavaScript + +This project fetches NASA facility data through a CORS proxy and dynamically displays each location as a card with its name, city, and state. +Each card includes a “Show weather” button that triggers a second fetch from the Open-Meteo API to display live conditions for that facility. +The interface is styled with a dark cosmic theme inspired by NASA imagery and designed for easy readability across hundreds of results. + +--- + +## Optimizations +- Add filters by state or region. +- Introduce a search bar for faster navigation. +- Include a “Hide weather” toggle. +- Experiment with data caching or lazy loading. +- Optionally visualize facility locations on a map. + +--- + +## Lessons Learned +- Working with nested fetch requests between two public APIs. +- Efficiently rendering large datasets with DOM manipulation. +- Managing hidden elements that reveal on user interaction. +- Maintaining clean, readable UI even with heavy data flow. +- Simplifying chained API logic without complex frameworks. + diff --git a/css/styles.css b/css/styles.css new file mode 100644 index 0000000..eec840e --- /dev/null +++ b/css/styles.css @@ -0,0 +1,102 @@ +* { + box-sizing: border-box; +} + +html, +body { + margin: 0; + padding: 0; + min-height: 100vh; + font-family: "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + color: #e8f1ff; + background: url("https://www.nasa.gov/wp-content/uploads/2023/07/hs-2015-02-a-large_web.jpg") center/cover no-repeat fixed; +} + +body::before { + content: ""; + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.65); + z-index: -1; +} + +h1 { + text-align: center; + margin: 28px auto 6px; + font-size: 32px; + font-weight: 800; + color: #a6e9ff; + letter-spacing: 0.5px; + text-shadow: 0 2px 10px rgba(0, 0, 0, 0.5); +} + +p { + text-align: center; + max-width: 800px; + margin: 8px auto; + color: #d2e5ff; + line-height: 1.4; +} + +#facilityList { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + gap: 20px; + padding: 24px; + width: 90%; + max-width: 1200px; + margin: 0 auto 60px; +} + +#facilityList li { + list-style: none; + background: rgba(20, 28, 52, 0.85); + border: 1px solid rgba(80, 100, 140, 0.4); + border-radius: 12px; + padding: 18px; + color: #eaf4ff; + display: flex; + flex-direction: column; + gap: 10px; + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +#facilityList li:hover { + transform: translateY(-2px); + box-shadow: 0 0 14px rgba(164, 200, 255, 0.25); +} + +button { + align-self: flex-start; + padding: 8px 14px; + background-color: #3b82f6; + color: #fff; + border: none; + border-radius: 8px; + font-size: 15px; + cursor: pointer; + transition: background-color 0.2s ease, transform 0.2s ease; +} + +button:hover { + background-color: #2563eb; + transform: scale(1.03); +} + + +.weather { + display: none; + background: rgba(35, 45, 75, 0.85); + border: 1px solid #506a9b; + border-radius: 8px; + padding: 10px; + font-size: 15px; + color: #eaf4ff; + line-height: 1.4; +} + + +#statusMsg { + margin-top: 10px; + color: #bcd6ff; +} \ No newline at end of file diff --git a/img/facility.png b/img/facility.png new file mode 100644 index 0000000..958c73e Binary files /dev/null and b/img/facility.png differ diff --git a/img/stars.avif b/img/stars.avif new file mode 100644 index 0000000..779632e Binary files /dev/null and b/img/stars.avif differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..d1093fe --- /dev/null +++ b/index.html @@ -0,0 +1,14 @@ + + + + + + + + +

NASA Facilities

+

Loading…

+
+ + + \ No newline at end of file diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..5f43b3d --- /dev/null +++ b/js/main.js @@ -0,0 +1,80 @@ +const statusMsg = document.querySelector("#statusMsg"); +const list = document.querySelector("#facilityList"); + +// keep proxy link +const nasaURL = "https://corsproxy.io/?url=https://data.nasa.gov/docs/legacy/gvk9-iz74.json"; + +fetch(nasaURL) + .then(res => res.json()) + .then(data => { + const facilities = data; + + if (!facilities || !facilities.length) { + statusMsg.textContent = "No facilities found."; + return; + } + + statusMsg.textContent = "NASA facilities loaded. Click 'Show weather' to view conditions."; + + facilities.forEach(facility => { + const name = facility.facility || "Unknown Facility"; + const center = facility.center || "Unknown Center"; + const city = facility.city || ""; + const state = facility.state || ""; + const lat = facility.location && facility.location.latitude; + const lon = facility.location && facility.location.longitude; + + // create card + const li = document.createElement("li"); + + const title = document.createElement("div"); + title.textContent = `${center} — ${name} (${city}, ${state})`; + li.appendChild(title); + + // weather button + const btn = document.createElement("button"); + btn.textContent = "Show weather"; + + // weather box + const weather = document.createElement("div"); + weather.className = "weather"; + weather.style.display = "none"; // start hidden + + // show weather when clicked + btn.addEventListener("click", () => { + weather.style.display = "block"; // make it visible + + if (!lat || !lon) { + weather.textContent = "No coordinates available."; + return; + } + + weather.textContent = "Loading weather..."; + + const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}¤t_weather=true`; + + fetch(weatherUrl) + .then(res => res.json()) + .then(data => { + const current = data.current_weather; + if (current) { + weather.textContent = `Temp: ${current.temperature}°C | Wind: ${current.windspeed} m/s`; + } else { + weather.textContent = "No weather data found."; + } + }) + .catch(err => { + console.log("Error:", err); + weather.textContent = "Error fetching weather."; + }); + }); + + li.appendChild(btn); + li.appendChild(weather); + list.appendChild(li); + }); + }) + .catch(err => { + console.log("Error:", err); + statusMsg.textContent = "Error loading NASA data. Please reload."; + });