├── src ├── index.css ├── assets │ ├── house.png │ └── weather-cloudy.png ├── components │ ├── Header.jsx │ ├── Footer.jsx │ ├── WeatherCard.jsx │ └── Search.jsx ├── main.jsx ├── App.jsx └── App.css ├── public └── weather-cloudy.png ├── vite.config.js ├── .gitignore ├── .eslintrc.cjs ├── index.html └── package.json /src/index.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/house.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hazrat-Ali9/Weather-Wise/HEAD/src/assets/house.png -------------------------------------------------------------------------------- /public/weather-cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hazrat-Ali9/Weather-Wise/HEAD/public/weather-cloudy.png -------------------------------------------------------------------------------- /src/assets/weather-cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hazrat-Ali9/Weather-Wise/HEAD/src/assets/weather-cloudy.png -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | 9 | // Vite config -------------------------------------------------------------------------------- /src/components/Header.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Header = () => { 4 | return ( 5 |
6 |

Weather Wise ⛅

7 |
8 | ) 9 | } 10 | 11 | export default Header -------------------------------------------------------------------------------- /src/components/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import House from '../assets/house.png' 3 | 4 | const Footer = () => { 5 | return ( 6 | 9 | ) 10 | } 11 | 12 | export default Footer -------------------------------------------------------------------------------- /src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.jsx' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')).render( 7 | 8 | 9 | , 10 | ) 11 | 12 | // Main js -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | .env 26 | .gitignore -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:react/recommended', 7 | 'plugin:react/jsx-runtime', 8 | 'plugin:react-hooks/recommended', 9 | ], 10 | ignorePatterns: ['dist', '.eslintrc.cjs'], 11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 12 | settings: { react: { version: '18.2' } }, 13 | plugins: ['react-refresh'], 14 | rules: { 15 | 'react-refresh/only-export-components': [ 16 | 'warn', 17 | { allowConstantExport: true }, 18 | ], 19 | }, 20 | } 21 | 22 | //.eslintrc -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Weather Wise 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import Header from './components/Header' 3 | import Search from './components/Search' 4 | import WeatherCard from './components/WeatherCard' 5 | import Footer from './components/Footer' 6 | import './App.css' 7 | 8 | const App = () => { 9 | const [weatherDetails, setWeatherDetails] = useState(null); 10 | 11 | return ( 12 |
13 |
14 |
15 | 16 | {weatherDetails && } 17 |
19 |
20 | ) 21 | } 22 | 23 | export default App 24 | 25 | // Apps js -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "weather-wise", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "axios": "^1.6.8", 14 | "react": "^18.2.0", 15 | "react-dom": "^18.2.0" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^18.2.43", 19 | "@types/react-dom": "^18.2.17", 20 | "@vitejs/plugin-react": "^4.2.1", 21 | "eslint": "^8.55.0", 22 | "eslint-plugin-react": "^7.33.2", 23 | "eslint-plugin-react-hooks": "^4.6.0", 24 | "eslint-plugin-react-refresh": "^0.4.5", 25 | "vite": "^5.0.8" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/components/WeatherCard.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import WeatherCloudy from '../assets/weather-cloudy.png' 3 | 4 | const WeatherCard = ({weatherDetails}) => { 5 | console.log(weatherDetails); 6 | return ( 7 |
8 |
9 |
10 | {weatherDetails.current.temp_c}o 11 |
12 |
13 | 14 | 🌈 {weatherDetails.current.humidity} 15 | 16 | 17 | 🌥️ {weatherDetails.current.cloud} 18 | 19 |
20 |
21 | {weatherDetails.location.name}, {weatherDetails.location.region}, {weatherDetails.location.country} 22 |
23 |
24 | 25 |
26 |
27 |
28 | ) 29 | } 30 | 31 | export default WeatherCard 32 | 33 | // Weather Card -------------------------------------------------------------------------------- /src/components/Search.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import axios from 'axios'; 3 | 4 | const Search = ({setWeatherDetails}) => { 5 | const [search, setSearch] = useState(""); 6 | 7 | const handleInput = (e) => { 8 | setSearch(e.target.value); 9 | setWeatherDetails(null); 10 | } 11 | 12 | const handleKeyDown = async (e) => { 13 | if(e.key != 'Enter') return; 14 | 15 | const options = { 16 | method: 'GET', 17 | url: 'https://weatherapi-com.p.rapidapi.com/current.json', 18 | params: {q: search}, 19 | headers: { 20 | 'X-RapidAPI-Key': import.meta.env.VITE_API_KEY, 21 | 'X-RapidAPI-Host': 'weatherapi-com.p.rapidapi.com' 22 | } 23 | }; 24 | 25 | try { 26 | const response = await axios.request(options); 27 | // console.log(response.data); 28 | setWeatherDetails(response.data); 29 | } catch (error) { 30 | console.error(error); 31 | } 32 | } 33 | 34 | return ( 35 |
36 |
37 | 38 | 39 | 40 | 41 | 47 |
48 |
49 | ) 50 | } 51 | 52 | export default Search -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | font-family: 'Poppins', sans-serif; 9 | color: white; 10 | max-width: 100vw; 11 | min-height: 100vh; 12 | background: linear-gradient(168.44deg, #2e335a 1.62%, #1c1333 95.72%); 13 | } 14 | 15 | .app { 16 | padding: 10px; 17 | } 18 | 19 | .app-container { 20 | max-width: 600px; 21 | margin: auto; 22 | } 23 | 24 | .header { 25 | padding: 20px 0; 26 | } 27 | 28 | .header h1 { 29 | font-weight: 400; 30 | font-size: 28px; 31 | letter-spacing: 2px; 32 | } 33 | 34 | footer { 35 | position: fixed; 36 | bottom: -60px; 37 | justify-items: center; 38 | text-align: center; 39 | } 40 | 41 | .search-section { 42 | margin-top: 20px; 43 | } 44 | 45 | .search-container { 46 | width: 100%; 47 | height: 36px; 48 | display: flex; 49 | align-items: center; 50 | padding: 10px 8px; 51 | background: linear-gradient(168.44deg, #2e335a 1.62%, #1c1333 95.72%); 52 | box-shadow: inset 0px 4px 4px rgba(0, 0, 0, .25); 53 | border-radius: 10px; 54 | } 55 | 56 | .search-container svg { 57 | width: 22px; 58 | height: 22px; 59 | } 60 | 61 | .search-container input { 62 | background: transparent; 63 | border: none; 64 | outline: none; 65 | width: 100%; 66 | height: 100%; 67 | padding: 0 10px; 68 | font-size: 16px; 69 | color: white; 70 | } 71 | 72 | .weather-section { 73 | margin-top: 50px; 74 | padding: 10px; 75 | } 76 | 77 | .weather-card { 78 | width: 100%; 79 | min-height: 184px; 80 | background: linear-gradient(90deg, #5936b4 0%, #362a84 103.55%); 81 | border-radius: 20px; 82 | position: relative; 83 | padding: 20px; 84 | display: flex; 85 | flex-direction: column; 86 | } 87 | 88 | .weather-temp-c { 89 | font-size: 64px; 90 | font-weight: 400; 91 | } 92 | 93 | .weather-info { 94 | display: flex; 95 | gap: 15px; 96 | align-items: center; 97 | color: #bbbbbb; 98 | } 99 | 100 | .weather-place { 101 | font-size: 22px; 102 | } 103 | 104 | .weather-avatar { 105 | position: absolute; 106 | top: -60px; 107 | right: -15px; 108 | } --------------------------------------------------------------------------------