Skip to content

Commit cfe909c

Browse files
committed
Resolve conflict: use remote version
2 parents 15bb6f9 + 165122f commit cfe909c

File tree

8 files changed

+796
-954
lines changed

8 files changed

+796
-954
lines changed

README.md

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
**ReactVerse** is an open-source API dashboard built with **React + Vite**, designed to help developers explore, visualize, and learn how to integrate public APIs safely and responsibly.
44
It’s more than just a project — it’s a **community-driven learning space** for understanding how APIs work, managing data securely, and contributing meaningfully to open source.
55

6-
Perfect for **Hacktoberfest**, **beginners**, and **API enthusiasts** who want to get hands-on experience using real-world APIs.
6+
Perfect for **beginners**, and **API enthusiasts** who want to get hands-on experience using real-world APIs.
77

88
---
99

@@ -76,22 +76,6 @@ We welcome contributions of all levels — from design tweaks to feature enhance
7676

7777
---
7878

79-
## 📚 API Reference
80-
81-
| Category | API | Documentation |
82-
| -------- | ----------------- | ----------------------------------------------------------------------------------------------------- |
83-
| Weather | wttr.in | [https://wttr.in/:help](https://wttr.in/:help) |
84-
| Crypto | CoinGecko | [https://www.coingecko.com/en/api](https://www.coingecko.com/en/api) |
85-
| Space | Open Notify | [http://open-notify.org/Open-Notify-API/](http://open-notify.org/Open-Notify-API/) |
86-
| Movies | Studio Ghibli | [https://ghibliapi.vercel.app/](https://ghibliapi.vercel.app/) |
87-
| Recipes | TheMealDB | [https://www.themealdb.com/api.php](https://www.themealdb.com/api.php) |
88-
| Trivia | Open Trivia DB | [https://opentdb.com/api_config.php](https://opentdb.com/api_config.php) |
89-
| Jokes | Official Joke API | [https://official-joke-api.appspot.com/](https://official-joke-api.appspot.com/) |
90-
| Quotes | Quotable | [https://github.com/lukePeavey/quotable](https://github.com/lukePeavey/quotable) |
91-
| Pets | Dog CEO / Cataas | [https://dog.ceo/dog-api/](https://dog.ceo/dog-api/) / [https://cataas.com/#/](https://cataas.com/#/) |
92-
| COVID-19 | COVID19 API | [https://covid19api.com/](https://covid19api.com/) |
93-
94-
---
9579

9680
## 🪪 License
9781

src/App.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,13 @@ export default function App() {
5959
<Route path="/" element={<Home />} />
6060
<Route path="/weather" element={<Weather />} />
6161
<Route path="/crypto" element={<Crypto />} />
62-
<Route path="/space" element={<Space />} />
62+
<Route path="/space" element={<Space theme={theme} />} />
6363
<Route path="/movies" element={<Movies />} />
6464
<Route path="/recipes" element={<Recipes />} />
6565
<Route path="/trivia" element={<Trivia />} />
6666
<Route path="/jokes-quotes" element={<JokesQuotes />} />
6767
<Route path="/pets" element={<Pets />} />
68-
<Route path="/covid" element={<Covid />} />
68+
<Route path="/covid" element={<Covid />} />
6969
</Routes>
7070
</main>
7171
</div>

src/components/Skeleton.jsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import React from 'react';
2+
3+
const Skeleton = ({width, height}) => {
4+
return (
5+
<span className="skeleton" style={{width:`${width}`, height:`${height}`}}></span>
6+
)
7+
}
8+
9+
export default Skeleton;

src/pages/Covid.jsx

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* - [ ] Offline cache last fetch
1818
* - [ ] Extract service + hook (useCovidSummary, useCountryTrends)
1919
*/
20-
import { useEffect, useState } from 'react';
20+
import { useEffect, useState, useCallback } from 'react';
2121
import Loading from '../components/Loading.jsx';
2222
import ErrorMessage from '../components/ErrorMessage.jsx';
2323
import Card from '../components/Card.jsx';
@@ -28,26 +28,39 @@ export default function Covid() {
2828
const [error, setError] = useState(null);
2929
const [country, setCountry] = useState('');
3030

31-
useEffect(() => { fetchSummary(); }, []);
32-
33-
async function fetchSummary() {
31+
const fetchSummary = useCallback(async () => {
32+
if (loading) return;
3433
try {
35-
setLoading(true); setError(null);
34+
setLoading(true);
35+
setError(null);
3636
const res = await fetch('https://api.covid19api.com/summary');
3737
if (!res.ok) throw new Error('Failed to fetch');
3838
const json = await res.json();
3939
setSummary(json);
40-
} catch (e) { setError(e); } finally { setLoading(false); }
41-
}
40+
} catch (e) {
41+
setError(e);
42+
} finally {
43+
setLoading(false);
44+
}
45+
}, [loading]);
46+
47+
useEffect(() => {
48+
fetchSummary();
49+
}, []);
4250

4351
const global = summary?.Global;
4452
const countries = summary?.Countries || [];
4553
const selected = countries.find(c => c.Slug === country);
4654

4755
return (
4856
<div>
57+
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem', flexWrap: 'wrap' }}>
4958
<h2>COVID-19 Tracker</h2>
50-
{loading && <Loading />}
59+
<button onClick={fetchSummary} disabled={loading}>
60+
{loading ? 'Refreshing...' : 'Refresh'}
61+
</button>
62+
</div>
63+
{loading && !summary && <Loading />}
5164
<ErrorMessage error={error} />
5265
{global && (
5366
<Card title="Global Stats">

src/pages/Space.jsx

Lines changed: 175 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
* ---------------------------------
44
* Easy:
55
* - [x] Refresh button / auto-refresh interval selector
6-
* - [ ] Show last updated timestamp
7-
* - [ ] Style astronauts list with craft grouping
6+
* - [x] Show last updated timestamp
7+
* - [x] Style astronauts list with craft grouping
88
* - [ ] Add loading skeleton or placeholder map area
99
* Medium:
1010
* - [ ] Integrate Leaflet map w/ marker at ISS coords
@@ -24,13 +24,16 @@ import Card from '../components/Card.jsx';
2424
import IssMap from '../components/IssMap.jsx';
2525
import DashboardControls from "../components/DashboardControls.jsx";
2626

27-
export default function Space() {
27+
28+
export default function Space({ theme = 'light' }) {
2829
const [iss, setIss] = useState(null);
2930
const [crew, setCrew] = useState([]);
3031
const [error, setError] = useState(null);
3132
const [loading, setLoading] = useState(false);
3233
const [lastUpdated, setLastUpdated] = useState(null);
33-
34+
35+
const isDark = theme === 'dark';
36+
3437
// Fetch both ISS position + crew
3538
async function fetchData() {
3639
try {
@@ -56,34 +59,177 @@ export default function Space() {
5659
useEffect(() => {
5760
fetchData();
5861
}, []);
59-
60-
//leaflet map component
62+
63+
// Proper dark/light theme colors
64+
const bgColor = isDark ? '#0f172a' : '#f8fafc';
65+
const textColor = isDark ? '#f1f5f9' : '#1e293b';
66+
const cardBg = isDark ? '#1e293b' : '#ffffff';
67+
const subText = isDark ? '#94a3b8' : '#64748b';
68+
const accent = isDark ? '#38bdf8' : '#2563eb';
69+
const listBg = isDark ? '#334155' : '#f1f5f9';
70+
const borderColor = isDark ? '#334155' : '#e2e8f0';
71+
6172
return (
62-
<div>
63-
<h2>Space & Astronomy</h2>
64-
<DashboardControls onRefresh={fetchData} />
73+
<div
74+
style={{
75+
maxWidth: '1000px',
76+
margin: '2rem auto',
77+
padding: '2rem',
78+
backgroundColor: bgColor,
79+
borderRadius: '16px',
80+
boxShadow: isDark
81+
? '0 4px 10px rgba(0,0,0,0.3)'
82+
: '0 4px 10px rgba(0,0,0,0.08)',
83+
color: textColor,
84+
fontFamily: 'Inter, system-ui, sans-serif',
85+
transition: 'background-color 0.3s ease, color 0.3s ease',
86+
border: isDark ? '1px solid #334155' : 'none',
87+
}}
88+
>
89+
<h2
90+
style={{
91+
textAlign: 'center',
92+
marginBottom: '1.8rem',
93+
fontSize: '2rem',
94+
fontWeight: '600',
95+
color: accent,
96+
letterSpacing: '0.5px',
97+
}}
98+
>
99+
🌌 Space & Astronomy Dashboard
100+
</h2>
101+
102+
<div style={{ display: 'flex', justifyContent: 'center', marginBottom: '1.5rem' }}>
103+
<DashboardControls onRefresh={fetchData} />
104+
</div>
105+
65106
{loading && <Loading />}
66107
<ErrorMessage error={error} />
67-
{iss && (
68-
<Card title="ISS Current Location">
69-
<p>Latitude: {iss.iss_position.latitude}</p>
70-
<p>Longitude: {iss.iss_position.longitude}</p>
71-
{lastUpdated && (
72-
<p style={{ fontSize: '0.8rem', color: '#666' }}>
73-
Last updated: {lastUpdated.toLocaleTimeString()}
74-
</p>
75-
)}
76-
<IssMap latitude={iss.iss_position.latitude} longitude={iss.iss_position.longitude} />
108+
109+
<div
110+
style={{
111+
display: 'flex',
112+
flexDirection: 'column',
113+
gap: '1.5rem',
114+
justifyContent: 'center',
115+
}}
116+
>
117+
{iss && (
118+
<Card
119+
title="🛰️ ISS Current Location"
120+
style={{
121+
backgroundColor: cardBg,
122+
borderRadius: '12px',
123+
padding: '1.5rem',
124+
boxShadow: isDark
125+
? '0 2px 8px rgba(0,0,0,0.2)'
126+
: '0 2px 8px rgba(0,0,0,0.05)',
127+
transition: 'all 0.3s ease',
128+
border: `1px solid ${borderColor}`,
129+
}}
130+
>
131+
<div style={{ lineHeight: '1.6' }}>
132+
<p style={{ color: textColor, margin: '0.5rem 0' }}>
133+
<strong>Latitude:</strong> {iss.iss_position.latitude}
134+
</p>
135+
<p style={{ color: textColor, margin: '0.5rem 0' }}>
136+
<strong>Longitude:</strong> {iss.iss_position.longitude}
137+
</p>
138+
{lastUpdated && (
139+
<p style={{ fontSize: '0.9rem', color: subText, margin: '0.5rem 0' }}>
140+
Last updated: {lastUpdated.toLocaleTimeString()}
141+
</p>
142+
)}
143+
</div>
144+
145+
<div style={{ marginTop: '1rem' }}>
146+
<IssMap
147+
latitude={iss.iss_position.latitude}
148+
longitude={iss.iss_position.longitude}
149+
/>
150+
</div>
151+
</Card>
152+
)}
153+
154+
<Card
155+
title={`👩‍🚀 Astronauts in Space (${crew.length})`}
156+
style={{
157+
backgroundColor: cardBg,
158+
borderRadius: '12px',
159+
padding: '1.5rem',
160+
boxShadow: isDark
161+
? '0 2px 8px rgba(0,0,0,0.2)'
162+
: '0 2px 8px rgba(0,0,0,0.05)',
163+
transition: 'all 0.3s ease',
164+
border: `1px solid ${borderColor}`,
165+
}}
166+
>
167+
<ul style={{
168+
paddingLeft: '0',
169+
listStyleType: 'none',
170+
margin: '0',
171+
display: 'flex',
172+
flexDirection: 'column',
173+
gap: '0.5rem'
174+
}}>
175+
{crew.map((p) => (
176+
<li
177+
key={p.name}
178+
style={{
179+
backgroundColor: listBg,
180+
padding: '0.75rem 1rem',
181+
borderRadius: '8px',
182+
display: 'flex',
183+
justifyContent: 'space-between',
184+
alignItems: 'center',
185+
transition: 'all 0.3s ease',
186+
border: `1px solid ${borderColor}`,
187+
}}
188+
>
189+
<span style={{
190+
fontWeight: '500',
191+
color: textColor
192+
}}>
193+
{p.name}
194+
</span>
195+
<span style={{
196+
fontSize: '0.9rem',
197+
color: subText,
198+
backgroundColor: isDark ? '#475569' : '#e2e8f0',
199+
padding: '0.25rem 0.75rem',
200+
borderRadius: '6px',
201+
fontWeight: '500'
202+
}}>
203+
🚀 {p.craft}
204+
</span>
205+
</li>
206+
))}
207+
</ul>
77208
</Card>
78-
)}
79-
<Card title={`Astronauts in Space (${crew.length})`}>
80-
<ul>
81-
{crew.map(p => (
82-
<li key={p.name}>{p.name}{p.craft}</li>
83-
))}
84-
</ul>
85-
</Card>
86-
{/* TODO: Add next ISS pass prediction form */}
209+
</div>
210+
211+
<p
212+
style={{
213+
marginTop: '2rem',
214+
textAlign: 'center',
215+
fontSize: '0.9rem',
216+
color: subText,
217+
}}
218+
>
219+
Data sourced from{' '}
220+
<a
221+
href="http://api.open-notify.org"
222+
style={{
223+
color: accent,
224+
textDecoration: 'none',
225+
fontWeight: '500',
226+
}}
227+
onMouseEnter={(e) => e.target.style.textDecoration = 'underline'}
228+
onMouseLeave={(e) => e.target.style.textDecoration = 'none'}
229+
>
230+
Open Notify API
231+
</a>
232+
</p>
87233
</div>
88234
);
89-
}
235+
}

0 commit comments

Comments
 (0)