├── 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 |
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 |
18 |
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 |
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 | }
--------------------------------------------------------------------------------