New Weather Modal
324
package-lock.json
generated
@@ -30,7 +30,8 @@
|
||||
"react-icons": "^5.4.0",
|
||||
"react-query": "^3.39.3",
|
||||
"react-router-dom": "^7.1.2",
|
||||
"react-toastify": "^11.0.3"
|
||||
"react-toastify": "^11.0.3",
|
||||
"recharts": "^2.15.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.10.7",
|
||||
@@ -2141,6 +2142,60 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
||||
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="
|
||||
},
|
||||
"node_modules/@types/d3-array": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz",
|
||||
"integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg=="
|
||||
},
|
||||
"node_modules/@types/d3-color": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
|
||||
"integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="
|
||||
},
|
||||
"node_modules/@types/d3-ease": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz",
|
||||
"integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="
|
||||
},
|
||||
"node_modules/@types/d3-interpolate": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
|
||||
"integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
|
||||
"dependencies": {
|
||||
"@types/d3-color": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/d3-path": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz",
|
||||
"integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="
|
||||
},
|
||||
"node_modules/@types/d3-scale": {
|
||||
"version": "4.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz",
|
||||
"integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==",
|
||||
"dependencies": {
|
||||
"@types/d3-time": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/d3-shape": {
|
||||
"version": "3.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz",
|
||||
"integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==",
|
||||
"dependencies": {
|
||||
"@types/d3-path": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/d3-time": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz",
|
||||
"integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="
|
||||
},
|
||||
"node_modules/@types/d3-timer": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz",
|
||||
"integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="
|
||||
},
|
||||
"node_modules/@types/eslint": {
|
||||
"version": "8.56.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz",
|
||||
@@ -3022,6 +3077,116 @@
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
||||
},
|
||||
"node_modules/d3-array": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
|
||||
"integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
|
||||
"dependencies": {
|
||||
"internmap": "1 - 2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-color": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
|
||||
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-ease": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
|
||||
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-format": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
|
||||
"integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-interpolate": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
|
||||
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
|
||||
"dependencies": {
|
||||
"d3-color": "1 - 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-path": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
|
||||
"integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-scale": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
|
||||
"integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
|
||||
"dependencies": {
|
||||
"d3-array": "2.10.0 - 3",
|
||||
"d3-format": "1 - 3",
|
||||
"d3-interpolate": "1.2.0 - 3",
|
||||
"d3-time": "2.1.1 - 3",
|
||||
"d3-time-format": "2 - 4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-shape": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
|
||||
"integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
|
||||
"dependencies": {
|
||||
"d3-path": "^3.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-time": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
|
||||
"integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
|
||||
"dependencies": {
|
||||
"d3-array": "2 - 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-time-format": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
|
||||
"integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
|
||||
"dependencies": {
|
||||
"d3-time": "1 - 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-timer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
|
||||
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.13",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
|
||||
@@ -3049,6 +3214,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/decimal.js-light": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
|
||||
"integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="
|
||||
},
|
||||
"node_modules/deep-eql": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
|
||||
@@ -3074,6 +3244,15 @@
|
||||
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
|
||||
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
|
||||
},
|
||||
"node_modules/dom-helpers": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
|
||||
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.7",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.4.7",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
|
||||
@@ -3469,6 +3648,11 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eventemitter3": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
|
||||
},
|
||||
"node_modules/expect-type": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz",
|
||||
@@ -3483,6 +3667,14 @@
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||
},
|
||||
"node_modules/fast-equals": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.2.2.tgz",
|
||||
"integrity": "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
|
||||
@@ -3887,6 +4079,14 @@
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"node_modules/internmap": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
|
||||
"integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/is-arrayish": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||
@@ -4206,8 +4406,7 @@
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
@@ -4215,6 +4414,17 @@
|
||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/loupe": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz",
|
||||
@@ -4422,6 +4632,14 @@
|
||||
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/oblivious-set": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/oblivious-set/-/oblivious-set-1.0.0.tgz",
|
||||
@@ -4663,6 +4881,16 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types": {
|
||||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
@@ -4850,6 +5078,20 @@
|
||||
"react-dom": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/react-smooth": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz",
|
||||
"integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==",
|
||||
"dependencies": {
|
||||
"fast-equals": "^5.0.1",
|
||||
"prop-types": "^15.8.1",
|
||||
"react-transition-group": "^4.4.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-style-singleton": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
|
||||
@@ -4899,6 +5141,56 @@
|
||||
"react-dom": "^18 || ^19"
|
||||
}
|
||||
},
|
||||
"node_modules/react-transition-group": {
|
||||
"version": "4.4.5",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
||||
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"dom-helpers": "^5.0.1",
|
||||
"loose-envify": "^1.4.0",
|
||||
"prop-types": "^15.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.6.0",
|
||||
"react-dom": ">=16.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/recharts": {
|
||||
"version": "2.15.1",
|
||||
"resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.1.tgz",
|
||||
"integrity": "sha512-v8PUTUlyiDe56qUj82w/EDVuzEFXwEHp9/xOowGAZwfLjB9uAy3GllQVIYMWF6nU+qibx85WF75zD7AjqoT54Q==",
|
||||
"dependencies": {
|
||||
"clsx": "^2.0.0",
|
||||
"eventemitter3": "^4.0.1",
|
||||
"lodash": "^4.17.21",
|
||||
"react-is": "^18.3.1",
|
||||
"react-smooth": "^4.0.4",
|
||||
"recharts-scale": "^0.4.4",
|
||||
"tiny-invariant": "^1.3.1",
|
||||
"victory-vendor": "^36.6.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/recharts-scale": {
|
||||
"version": "0.4.5",
|
||||
"resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz",
|
||||
"integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==",
|
||||
"dependencies": {
|
||||
"decimal.js-light": "^2.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/recharts/node_modules/react-is": {
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
|
||||
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
|
||||
},
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
@@ -5321,6 +5613,11 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/tiny-invariant": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
|
||||
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="
|
||||
},
|
||||
"node_modules/tinybench": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
|
||||
@@ -5636,6 +5933,27 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/victory-vendor": {
|
||||
"version": "36.9.2",
|
||||
"resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz",
|
||||
"integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==",
|
||||
"dependencies": {
|
||||
"@types/d3-array": "^3.0.3",
|
||||
"@types/d3-ease": "^3.0.0",
|
||||
"@types/d3-interpolate": "^3.0.1",
|
||||
"@types/d3-scale": "^4.0.2",
|
||||
"@types/d3-shape": "^3.1.0",
|
||||
"@types/d3-time": "^3.0.0",
|
||||
"@types/d3-timer": "^3.0.0",
|
||||
"d3-array": "^3.1.6",
|
||||
"d3-ease": "^3.0.1",
|
||||
"d3-interpolate": "^3.0.1",
|
||||
"d3-scale": "^4.0.2",
|
||||
"d3-shape": "^3.1.0",
|
||||
"d3-time": "^3.0.0",
|
||||
"d3-timer": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.0.7",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.0.7.tgz",
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
"react-icons": "^5.4.0",
|
||||
"react-query": "^3.39.3",
|
||||
"react-router-dom": "^7.1.2",
|
||||
"react-toastify": "^11.0.3"
|
||||
"react-toastify": "^11.0.3",
|
||||
"recharts": "^2.15.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.10.7",
|
||||
@@ -41,6 +42,8 @@
|
||||
"@typescript-eslint/eslint-plugin": "^8.20.0",
|
||||
"@typescript-eslint/parser": "^8.20.0",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"@vitest/coverage-v8": "^3.0.2",
|
||||
"@vitest/ui": "^3.0.2",
|
||||
"eslint": "^9.18.0",
|
||||
"eslint-plugin-react-hooks": "^5.1.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.18",
|
||||
@@ -49,8 +52,6 @@
|
||||
"vite-plugin-dts": "~4.5.0",
|
||||
"vite-plugin-eslint": "^1.8.1",
|
||||
"vite-tsconfig-paths": "^5.1.4",
|
||||
"vitest": "^3.0.2",
|
||||
"@vitest/coverage-v8": "^3.0.2",
|
||||
"@vitest/ui": "^3.0.2"
|
||||
"vitest": "^3.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
1
src/assets/weather/cloudy.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path fill="#BBDEFB" d="M29.5 12A8.5 8.5 0 1 0 29.5 29A8.5 8.5 0 1 0 29.5 12Z"/><path fill="#BBDEFB" d="M37 21.893A7 7 0 1 0 37 35.893 7 7 0 1 0 37 21.893zM11 22A7 7 0 1 0 11 36 7 7 0 1 0 11 22z"/><path fill="#BBDEFB" d="M17.5 15A6.5 6.5 0 1 0 17.5 28A6.5 6.5 0 1 0 17.5 15Z"/><path fill="#BBDEFB" d="M25 19.893A7 7 0 1 0 25 33.893A7 7 0 1 0 25 19.893Z"/><path fill="#BBDEFB" d="M7,32c0,2.209,1.791,4,4,4h25c2.209,0,4-1.791,4-4v-1c0-2.209-1.791-4-4-4H11c-2.209,0-4,1.791-4,4V32z"/></svg>
|
||||
|
After Width: | Height: | Size: 570 B |
1
src/assets/weather/haze.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path fill="#FF9800" d="M24,6L6,24l1,1h1c1.104,0,2,0.896,2,2c0,0.293-0.066,0.569-0.18,0.82L23,41h2l17-17L24,6z"/><path fill="#FF9800" d="M11 11H37V37H11z"/><path fill="#FFEB3B" d="M13,24c0,6.077,4.923,11,11,11c6.076,0,11-4.923,11-11s-4.924-11-11-11C17.923,13,13,17.923,13,24"/><path fill="#64B5F6" d="M40,37h-9c-1.104,0-2-0.896-2-2s0.896-2,2-2h3c1.104,0,2-0.896,2-2s-0.896-2-2-2h-6h-3h-6c-1.104,0-2-0.896-2-2c0-1.102,0.89-1.994,1.99-1.999H21c1.104,0,2-0.896,2-2V23l0,0c0-1.104-0.896-2-2-2H7v0.001c-1.104,0-2,0.896-2,2s0.896,2,2,2h1C9.1,25.006,9.99,25.898,9.99,27c0,1.104-0.896,2-2,2H8c-1.104,0-2,0.896-2,2s0.896,2,2,2h1c1.104,0,2,0.896,2,2s-0.896,2-2,2s-2,0.896-2,2s0.896,2,2,2h31c0.8,0,1.485-0.473,1.805-1.152h0.001l0.001-0.002c0.057-0.123,0.104-0.25,0.135-0.385c0.002-0.008,0.006-0.016,0.008-0.023C41.98,39.296,42,39.15,42,39C42,37.896,41.104,37,40,37z"/><path fill="#BBDEFB" d="M24,35c4.273,0,7.969-2.44,9.79-6H28h-3h-6c-1.104,0-2-0.896-2-2c0-1.102,0.89-1.994,1.99-1.999H21c1.104,0,2-0.896,2-2V23c0-1.104-0.896-2-2-2h-7.576C13.154,21.955,13,22.959,13,24C13,30.077,17.923,35,24,35z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
1
src/assets/weather/heavy-rain.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path fill="#BBDEFB" d="M29.5 5A8.5 8.5 0 1 0 29.5 22A8.5 8.5 0 1 0 29.5 5Z"/><path fill="#BBDEFB" d="M37 14.893A7 7 0 1 0 37 28.893 7 7 0 1 0 37 14.893zM11 15A7 7 0 1 0 11 29 7 7 0 1 0 11 15z"/><path fill="#BBDEFB" d="M17.5 8A6.5 6.5 0 1 0 17.5 21A6.5 6.5 0 1 0 17.5 8Z"/><path fill="#BBDEFB" d="M25 12.893A7 7 0 1 0 25 26.893A7 7 0 1 0 25 12.893Z"/><path fill="#BBDEFB" d="M7,25c0,2.209,1.791,4,4,4h25c2.209,0,4-1.791,4-4v-1c0-2.209-1.791-4-4-4H11c-2.209,0-4,1.791-4,4V25z"/><g><path fill="#2196F3" d="M20 29A1 1 0 1 0 20 31 1 1 0 1 0 20 29zM34 29A1 1 0 1 0 34 31 1 1 0 1 0 34 29zM19 32A1 1 0 1 0 19 34 1 1 0 1 0 19 32zM18 35A1 1 0 1 0 18 37 1 1 0 1 0 18 35zM17 38A1 1 0 1 0 17 40 1 1 0 1 0 17 38zM33 32A1 1 0 1 0 33 34 1 1 0 1 0 33 32zM32 35A1 1 0 1 0 32 37 1 1 0 1 0 32 35zM31 38A1 1 0 1 0 31 40 1 1 0 1 0 31 38zM16 41A1 1 0 1 0 16 43 1 1 0 1 0 16 41zM30 41A1 1 0 1 0 30 43 1 1 0 1 0 30 41zM12 32A1 1 0 1 0 12 34 1 1 0 1 0 12 32zM11 35A1 1 0 1 0 11 37 1 1 0 1 0 11 35zM26 32A1 1 0 1 0 26 34 1 1 0 1 0 26 32zM25 35A1 1 0 1 0 25 37 1 1 0 1 0 25 35zM10 38A1 1 0 1 0 10 40 1 1 0 1 0 10 38zM24 38A1 1 0 1 0 24 40 1 1 0 1 0 24 38zM27 29A1 1 0 1 0 27 31 1 1 0 1 0 27 29zM13 29A1 1 0 1 0 13 31 1 1 0 1 0 13 29z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
src/assets/weather/partly-cloudy.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path fill="#FF9800" d="M8 10.001H25V27.000999999999998H8z"/><path fill="#FF9800" d="M7.661 9.661H25.339V27.339H7.661z" transform="rotate(-45.001 16.5 18.5)"/><path fill="#FFEB3B" d="M10,18.5c0,3.591,2.909,6.5,6.5,6.5s6.5-2.909,6.5-6.5S20.091,12,16.5,12S10,14.909,10,18.5"/><g><path fill="#BBDEFB" d="M29.5 17A8.5 8.5 0 1 0 29.5 34A8.5 8.5 0 1 0 29.5 17Z"/><path fill="#BBDEFB" d="M37 26.893A7 7 0 1 0 37 40.893 7 7 0 1 0 37 26.893zM11 27A7 7 0 1 0 11 41 7 7 0 1 0 11 27z"/><path fill="#BBDEFB" d="M17.5 20A6.5 6.5 0 1 0 17.5 33A6.5 6.5 0 1 0 17.5 20Z"/><path fill="#BBDEFB" d="M25 24.893A7 7 0 1 0 25 38.893A7 7 0 1 0 25 24.893Z"/><path fill="#BBDEFB" d="M7,37c0,2.209,1.791,4,4,4h25c2.209,0,4-1.791,4-4v-1c0-2.209-1.791-4-4-4H11c-2.209,0-4,1.791-4,4V37z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 851 B |
1
src/assets/weather/rain.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path fill="#BBDEFB" d="M29.5 5A8.5 8.5 0 1 0 29.5 22A8.5 8.5 0 1 0 29.5 5Z"/><path fill="#BBDEFB" d="M37 14.893A7 7 0 1 0 37 28.893 7 7 0 1 0 37 14.893zM11 15A7 7 0 1 0 11 29 7 7 0 1 0 11 15z"/><path fill="#BBDEFB" d="M17.5 8A6.5 6.5 0 1 0 17.5 21A6.5 6.5 0 1 0 17.5 8Z"/><path fill="#BBDEFB" d="M25 12.893A7 7 0 1 0 25 26.893A7 7 0 1 0 25 12.893Z"/><path fill="#BBDEFB" d="M7,25c0,2.209,1.791,4,4,4h25c2.209,0,4-1.791,4-4v-1c0-2.209-1.791-4-4-4H11c-2.209,0-4,1.791-4,4V25z"/><g><path fill="#2196F3" d="M34.95 37.15c-1.132 1.133-2.968 1.133-4.101 0-1.134-1.131-1.133-2.969 0-4.1C31.982 31.917 37 31 37 31S36.082 36.02 34.95 37.15zM23.95 41.15c-1.132 1.132-2.968 1.132-4.101 0-1.133-1.133-1.132-2.969 0-4.101 1.133-1.133 6.152-2.05 6.152-2.05S25.082 40.02 23.95 41.15zM13.95 37.15c-1.132 1.133-2.968 1.133-4.101 0-1.133-1.131-1.132-2.969 0-4.1 1.132-1.133 6.151-2.05 6.151-2.05S15.082 36.02 13.95 37.15z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 999 B |
1
src/assets/weather/sleet.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path fill="#BBDEFB" d="M29.5 5A8.5 8.5 0 1 0 29.5 22A8.5 8.5 0 1 0 29.5 5Z"/><path fill="#BBDEFB" d="M37 14.893A7 7 0 1 0 37 28.893 7 7 0 1 0 37 14.893zM11 15A7 7 0 1 0 11 29 7 7 0 1 0 11 15z"/><path fill="#BBDEFB" d="M17.5 8A6.5 6.5 0 1 0 17.5 21A6.5 6.5 0 1 0 17.5 8Z"/><path fill="#BBDEFB" d="M25 12.893A7 7 0 1 0 25 26.893A7 7 0 1 0 25 12.893Z"/><path fill="#BBDEFB" d="M7,25c0,2.209,1.791,4,4,4h25c2.209,0,4-1.791,4-4v-1c0-2.209-1.791-4-4-4H11c-2.209,0-4,1.791-4,4V25z"/><g><path fill="#2196F3" d="M35.95 37.15c-1.132 1.133-2.968 1.133-4.101 0-1.134-1.131-1.133-2.969 0-4.1C32.982 31.917 38 31 38 31S37.082 36.02 35.95 37.15zM14.95 37.15c-1.132 1.133-2.968 1.133-4.101 0-1.133-1.131-1.132-2.969 0-4.1 1.132-1.133 6.151-2.05 6.151-2.05S16.082 36.02 14.95 37.15zM23 34H25V43H23z"/><path fill="#2196F3" d="M23 33.999H25V42.999H23z" transform="rotate(120.471 24 38.499)"/><path fill="#2196F3" d="M23.001 34H24.999000000000002V43H23.001z" transform="rotate(60.679 24 38.5)"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
1
src/assets/weather/snow.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path fill="#BBDEFB" d="M29.5 5A8.5 8.5 0 1 0 29.5 22A8.5 8.5 0 1 0 29.5 5Z"/><path fill="#BBDEFB" d="M37 14.893A7 7 0 1 0 37 28.893 7 7 0 1 0 37 14.893zM11 15A7 7 0 1 0 11 29 7 7 0 1 0 11 15z"/><path fill="#BBDEFB" d="M17.5 8A6.5 6.5 0 1 0 17.5 21A6.5 6.5 0 1 0 17.5 8Z"/><path fill="#BBDEFB" d="M25 12.893A7 7 0 1 0 25 26.893A7 7 0 1 0 25 12.893Z"/><path fill="#BBDEFB" d="M7,25c0,2.209,1.791,4,4,4h25c2.209,0,4-1.791,4-4v-1c0-2.209-1.791-4-4-4H11c-2.209,0-4,1.791-4,4V25z"/><g><path fill="#2196F3" d="M23 34H25V43H23z"/><path fill="#2196F3" d="M23 33.999H25V42.999H23z" transform="rotate(120.471 24 38.499)"/><path fill="#2196F3" d="M23.001 34H24.999000000000002V43H23.001z" transform="rotate(60.679 24 38.5)"/><path fill="#2196F3" d="M10 31H12V40H10z"/><path fill="#2196F3" d="M10 30.999H12V39.998999999999995H10z" transform="rotate(120.444 11 35.5)"/><path fill="#2196F3" d="M10.001 31H11.998999999999999V40H10.001z" transform="rotate(60.679 11 35.5)"/><path fill="#2196F3" d="M36 31H38V40H36z"/><path fill="#2196F3" d="M35.999 30.998H37.999V39.998000000000005H35.999z" transform="rotate(120.458 36.999 35.5)"/><path fill="#2196F3" d="M36 31H37.998V40.001H36z" transform="rotate(60.679 36.999 35.5)"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
src/assets/weather/sunny.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path fill="#FF9800" d="M38,38c0,0-9-3-14-3s-14,3-14,3s3-10,3-14s-3-14-3-14s9,3,14,3s14-3,14-3s-3,10-3,14S38,38,38,38z"/><path fill="#FF9800" d="M43,24c0,0-8.222,4.778-11.222,7.778S24,43,24,43s-4.278-7.722-7.778-11.222S5,24,5,24s8.221-4.777,11.222-7.777S24,5,24,5s4.779,8.223,7.778,11.223S43,24,43,24z"/><path fill="#FFEB3B" d="M14,24c0,5.524,4.477,10,10,10s10-4.476,10-10s-4.477-10-10-10S14,18.476,14,24"/></svg>
|
||||
|
After Width: | Height: | Size: 496 B |
1
src/assets/weather/thunderstorm.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path fill="#BBDEFB" d="M18.5 4A8.5 8.5 0 1 0 18.5 21A8.5 8.5 0 1 0 18.5 4Z"/><path fill="#BBDEFB" d="M19 20A7 7 0 1 0 19 34A7 7 0 1 0 19 20Z"/><path fill="#BBDEFB" d="M11 14A7 7 0 1 0 11 28 7 7 0 1 0 11 14zM38 14A6 6 0 1 0 38 26 6 6 0 1 0 38 14z"/><path fill="#BBDEFB" d="M30 19A6 6 0 1 0 30 31A6 6 0 1 0 30 19Z"/><path fill="#BBDEFB" d="M30.5 7A6.5 6.5 0 1 0 30.5 20A6.5 6.5 0 1 0 30.5 7Z"/><path fill="#BBDEFB" d="M23 12A7 7 0 1 0 23 26A7 7 0 1 0 23 12Z"/><g><path fill="#D500F9" d="M22 44l2-7h-3l4-8h4l-3.594 6H29L22 44zM32.594 39l2-7h-3l4-8h4L36 30h3.594L32.594 39z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 666 B |
1
src/assets/weather/windy.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><path fill="#bbdefb" d="M38,15.5c0,4.7-3.8,8.5-8.5,8.5S21,20.2,21,15.5S24.8,7,29.5,7S38,10.8,38,15.5z"/><path fill="#bbdefb" d="M44 23.9c0 3.9-3.1 7-7 7s-7-3.1-7-7c0-3.9 3.1-7 7-7S44 20 44 23.9zM18 24c0 3.9-3.1 7-7 7s-7-3.1-7-7 3.1-7 7-7S18 20.1 18 24z"/><path fill="#bbdefb" d="M24,16.5c0,3.6-2.9,6.5-6.5,6.5S11,20.1,11,16.5s2.9-6.5,6.5-6.5S24,12.9,24,16.5z"/><path fill="#bbdefb" d="M32,21.9c0,3.9-3.1,7-7,7s-7-3.1-7-7c0-3.9,3.1-7,7-7S32,18,32,21.9z"/><path fill="#bbdefb" d="M7,27c0,2.2,1.8,4,4,4h25c2.2,0,4-1.8,4-4v-1c0-2.2-1.8-4-4-4H11c-2.2,0-4,1.8-4,4V27z"/><path fill="#2196f3" d="M31.9 41c-2.5 0-4.6-1.5-5.5-3.9-.2-.5.1-1.1.6-1.3.5-.2 1.1.1 1.3.6.6 1.7 2 2.7 3.7 2.6 2.3-.1 4-1.8 4-4 0-2.2-1.8-4-4-4H12c-.6 0-1-.4-1-1s.4-1 1-1h20c3.3 0 6 2.7 6 6 0 3.2-2.6 5.9-6 6C32 41 31.9 41 31.9 41zM25 27H14c-.6 0-1-.4-1-1s.4-1 1-1h11c1.6 0 3-1.4 3-3s-1.4-3-3-3c-1.2 0-2.3.8-2.8 1.9-.2.5-.8.8-1.3.6-.5-.2-.8-.8-.6-1.3.8-1.9 2.6-3.2 4.7-3.2 2.8 0 5 2.2 5 5S27.8 27 25 27z"/><path fill="#2196f3" d="M18,41c-1.5,0-2.9-0.8-3.5-2.2c-0.2-0.5,0-1.1,0.4-1.3c0.5-0.2,1.1,0,1.3,0.4c0.3,0.6,1,1,1.7,1 c1.1,0,2-0.9,2-2s-0.9-2-2-2h-8c-0.6,0-1-0.4-1-1s0.4-1,1-1h8c2.2,0,4,1.8,4,4S20.2,41,18,41z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
145
src/components/WeatherModal/CurrentWeather.tsx
Normal file
@@ -0,0 +1,145 @@
|
||||
import { Grid, Group, Stack, Text, ThemeIcon } from '@mantine/core';
|
||||
import { FaLongArrowAltDown, FaLongArrowAltUp, FaWind } from 'react-icons/fa';
|
||||
import { WiBarometer, WiHumidity } from 'react-icons/wi';
|
||||
import WeatherIcon from './WeatherIcon';
|
||||
|
||||
export default function CurrentWeather({ weather }: any) {
|
||||
return (
|
||||
<Stack
|
||||
gap={0}
|
||||
w={'100%'}
|
||||
justify='space-between'
|
||||
style={{
|
||||
backgroundColor: 'var(--color-search-background)',
|
||||
padding: '1rem',
|
||||
borderRadius: '8px',
|
||||
paddingBottom: '.5rem',
|
||||
}}
|
||||
>
|
||||
<Group gap={0} px={16} w={'100%'}>
|
||||
<Text
|
||||
c={'var(--color-text-pri)'}
|
||||
style={{
|
||||
fontSize: '1.375rem',
|
||||
textAlign: 'left',
|
||||
}}
|
||||
>
|
||||
Current Weather
|
||||
</Text>
|
||||
</Group>
|
||||
<Group gap={0} w={'100%'}>
|
||||
<Stack gap={0} w={'50%'}>
|
||||
<Group gap={0}>
|
||||
<WeatherIcon textDescription={`${weather.textDescription}`} />
|
||||
<Text fz={'7rem'} fw={200}>
|
||||
{weather.temperature}°<sup style={{ fontSize: '3rem' }}>F</sup>
|
||||
</Text>
|
||||
</Group>
|
||||
<Text
|
||||
c={'var(--color-text-pri)'}
|
||||
style={{
|
||||
fontSize: '1.375rem',
|
||||
textAlign: 'left',
|
||||
marginTop: -32,
|
||||
marginLeft: 16,
|
||||
}}
|
||||
>
|
||||
{weather.textDescription}
|
||||
</Text>
|
||||
</Stack>
|
||||
<Stack gap={4} w={'50%'}>
|
||||
<Text>
|
||||
Feels like {weather.heatIndex ?? weather.windChill ?? weather.temperature}°
|
||||
<sup>F</sup>
|
||||
</Text>
|
||||
<Grid align='center' w={'100%'}>
|
||||
<Grid.Col span={2}>
|
||||
<ThemeIcon
|
||||
h={'auto'}
|
||||
w={'auto'}
|
||||
variant='subtle'
|
||||
c={'var(--color-text-pri)'}
|
||||
>
|
||||
<FaLongArrowAltUp size={32} />
|
||||
</ThemeIcon>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={1}>
|
||||
<Text>
|
||||
{weather.highTemp}°<sup>F</sup>
|
||||
</Text>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={2}>
|
||||
<ThemeIcon
|
||||
h={'auto'}
|
||||
w={'auto'}
|
||||
variant='subtle'
|
||||
c={'var(--color-text-pri)'}
|
||||
>
|
||||
<FaLongArrowAltDown size={32} />
|
||||
</ThemeIcon>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={1}>
|
||||
<Text>
|
||||
{weather.lowTemp}°<sup>F</sup>
|
||||
</Text>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<Grid align='center'>
|
||||
<Grid.Col span={2}>
|
||||
<ThemeIcon
|
||||
h={'auto'}
|
||||
w={'auto'}
|
||||
variant='subtle'
|
||||
c={'var(--color-text-pri)'}
|
||||
>
|
||||
<WiHumidity size={32} />
|
||||
</ThemeIcon>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={2}>
|
||||
<Text>Humidity</Text>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={2}>
|
||||
<Text>{weather.humidity}%</Text>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<Grid align='center'>
|
||||
<Grid.Col span={2}>
|
||||
<ThemeIcon
|
||||
h={'auto'}
|
||||
w={'auto'}
|
||||
variant='subtle'
|
||||
c={'var(--color-text-pri)'}
|
||||
>
|
||||
<FaWind size={32} />
|
||||
</ThemeIcon>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={2}>
|
||||
<Text>Wind</Text>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={2}>
|
||||
<Text>{weather.windSpeed}mph</Text>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<Grid align='center'>
|
||||
<Grid.Col span={2}>
|
||||
<ThemeIcon
|
||||
h={'auto'}
|
||||
w={'auto'}
|
||||
variant='subtle'
|
||||
c={'var(--color-text-pri)'}
|
||||
>
|
||||
<WiBarometer size={32} />
|
||||
</ThemeIcon>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={2}>
|
||||
<Text>Pressure</Text>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={2}>
|
||||
<Text>{weather.pressure} in</Text>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Group>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
52
src/components/WeatherModal/ExtendedForecast.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { Group, Stack, Text } from '@mantine/core';
|
||||
import WeatherIcon from './WeatherIcon';
|
||||
|
||||
export default function ExtendedForecast({ forecast }: any) {
|
||||
const day = forecast.slice(2, 14).filter((item: any) => item.isDaytime);
|
||||
const night = forecast.slice(2, 14).filter((item: any) => !item.isDaytime);
|
||||
return (
|
||||
<Stack
|
||||
gap={0}
|
||||
w={'100%'}
|
||||
justify='space-between'
|
||||
style={{
|
||||
backgroundColor: 'var(--color-search-background)',
|
||||
padding: '1rem',
|
||||
borderRadius: '8px',
|
||||
paddingBottom: '.5rem',
|
||||
}}
|
||||
>
|
||||
<Group gap={0} px={16} w={'100%'}>
|
||||
<Text
|
||||
c={'var(--color-text-pri)'}
|
||||
style={{
|
||||
fontSize: '1.375rem',
|
||||
textAlign: 'left',
|
||||
}}
|
||||
>
|
||||
Extended Forecast
|
||||
</Text>
|
||||
</Group>
|
||||
<Group w={'100%'} align='center' justify='space-between'>
|
||||
{day.map((item: any, index: number) => {
|
||||
const short = item.shortForecast.includes('And')
|
||||
? item.shortForecast.substring(0, item.shortForecast.indexOf('And'))
|
||||
: item.shortForecast.includes('then')
|
||||
? item.shortForecast.substring(0, item.shortForecast.indexOf('then'))
|
||||
: item.shortForecast;
|
||||
return (
|
||||
<Stack key={item.name} gap={0} align='center'>
|
||||
<Text>{item.name}</Text>
|
||||
<WeatherIcon textDescription={short} />
|
||||
<Text>{short}</Text>
|
||||
<Text>
|
||||
{item.temperature}°{item.temperatureUnit}/{night[index].temperature}°
|
||||
{item.temperatureUnit}
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
})}
|
||||
</Group>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -94,7 +94,7 @@ export default function HourlyCard({ weather }: any) {
|
||||
color: 'white',
|
||||
}}
|
||||
>
|
||||
{weather.temperature}°{weather.temperatureUnit}/{weather.relativeHumidity.value}%
|
||||
{weather.temperature}°{weather.temperatureUnit}/{weather.relativeHumidity?.value}%
|
||||
</Text>
|
||||
<Box
|
||||
mt={4}
|
||||
@@ -114,7 +114,7 @@ export default function HourlyCard({ weather }: any) {
|
||||
transform: `rotate(${WindDirection[weather.windDirection]}deg)`,
|
||||
}}
|
||||
/>
|
||||
{`${weather.probabilityOfPrecipitation.value}`}%
|
||||
{`${weather.probabilityOfPrecipitation?.value}`}%
|
||||
</Group>
|
||||
</Box>
|
||||
</Stack>
|
||||
|
||||
251
src/components/WeatherModal/WeatherIcon.tsx
Normal file
@@ -0,0 +1,251 @@
|
||||
import { Image } from '@mantine/core';
|
||||
import CloudyIcon from '../../assets/weather/cloudy.svg';
|
||||
import HazeIcon from '../../assets/weather/haze.svg';
|
||||
import HeavyRainIcon from '../../assets/weather/heavy-rain.svg';
|
||||
import PartlyCloudyIcon from '../../assets/weather/partly-cloudy.svg';
|
||||
import RainIcon from '../../assets/weather/rain.svg';
|
||||
import SleetIcon from '../../assets/weather/sleet.svg';
|
||||
import SnowIcon from '../../assets/weather/snow.svg';
|
||||
import SunnyIcon from '../../assets/weather/sunny.svg';
|
||||
import ThunderstormIcon from '../../assets/weather/thunderstorm.svg';
|
||||
|
||||
export default function WeatherIcon({ textDescription }: { textDescription: string }) {
|
||||
const Icon = () => {
|
||||
switch (textDescription.trim()) {
|
||||
case 'Clear':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={SunnyIcon}
|
||||
alt='SunnyIcon'
|
||||
/>
|
||||
);
|
||||
case 'Cloudy':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={CloudyIcon}
|
||||
alt='CloudyIcon'
|
||||
/>
|
||||
);
|
||||
case 'Mostly Cloudy':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={CloudyIcon}
|
||||
alt='CloudyIcon'
|
||||
/>
|
||||
);
|
||||
case 'Rain':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={RainIcon}
|
||||
alt='RainIcon'
|
||||
/>
|
||||
);
|
||||
case 'Showers':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={RainIcon}
|
||||
alt='RainIcon'
|
||||
/>
|
||||
);
|
||||
case 'Drizzle':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={RainIcon}
|
||||
alt='RainIcon'
|
||||
/>
|
||||
);
|
||||
case 'Snow':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={SnowIcon}
|
||||
alt='SnowIcon'
|
||||
/>
|
||||
);
|
||||
case 'Thunderstorm':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={ThunderstormIcon}
|
||||
alt='ThunderstormIcon'
|
||||
/>
|
||||
);
|
||||
case 'Mist':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={HazeIcon}
|
||||
alt='HazeIcon'
|
||||
/>
|
||||
);
|
||||
case 'Haze':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={HazeIcon}
|
||||
alt='HazeIcon'
|
||||
/>
|
||||
);
|
||||
case 'Dust':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={HazeIcon}
|
||||
alt='HazeIcon'
|
||||
/>
|
||||
);
|
||||
case 'Fog':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={HazeIcon}
|
||||
alt='HazeIcon'
|
||||
/>
|
||||
);
|
||||
case 'Smoke':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={HazeIcon}
|
||||
alt='HazeIcon'
|
||||
/>
|
||||
);
|
||||
case 'Sand':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={HazeIcon}
|
||||
alt='HazeIcon'
|
||||
/>
|
||||
);
|
||||
case 'Ash':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={HazeIcon}
|
||||
alt='HazeIcon'
|
||||
/>
|
||||
);
|
||||
case 'Squall':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={HazeIcon}
|
||||
alt='HazeIcon'
|
||||
/>
|
||||
);
|
||||
case 'Tornado':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={HazeIcon}
|
||||
alt='HazeIcon'
|
||||
/>
|
||||
);
|
||||
case 'Freezing Rain':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={HazeIcon}
|
||||
alt='HazeIcon'
|
||||
/>
|
||||
);
|
||||
case 'Shower Rain':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={HazeIcon}
|
||||
alt='HazeIcon'
|
||||
/>
|
||||
);
|
||||
case 'Heavy Rain':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={HeavyRainIcon}
|
||||
alt='HeavyRainIcon'
|
||||
/>
|
||||
);
|
||||
case 'Scattered Clouds':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={PartlyCloudyIcon}
|
||||
alt='PartlyCloudyIcon'
|
||||
/>
|
||||
);
|
||||
case 'Broken Clouds':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={PartlyCloudyIcon}
|
||||
alt='PartlyCloudyIcon'
|
||||
/>
|
||||
);
|
||||
case 'Overcast Clouds':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={PartlyCloudyIcon}
|
||||
alt='PartlyCloudyIcon'
|
||||
/>
|
||||
);
|
||||
case 'Moderate Rain':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={PartlyCloudyIcon}
|
||||
alt='PartlyCloudyIcon'
|
||||
/>
|
||||
);
|
||||
case 'Light Rain':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={PartlyCloudyIcon}
|
||||
alt='PartlyCloudyIcon'
|
||||
/>
|
||||
);
|
||||
case 'Heavy Snow':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={SnowIcon}
|
||||
alt='SnowIcon'
|
||||
/>
|
||||
);
|
||||
case 'Sleet':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={SleetIcon}
|
||||
alt='SleetIcon'
|
||||
/>
|
||||
);
|
||||
case 'Partly Sunny':
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={PartlyCloudyIcon}
|
||||
alt='PartlyCloudyIcon'
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={SunnyIcon}
|
||||
alt='SunnyIcon'
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return <Icon />;
|
||||
}
|
||||
@@ -1,15 +1,26 @@
|
||||
import { Box, Center, Divider, Group, Modal, Stack, Text } from '@mantine/core';
|
||||
import { Center, Group, Modal, Stack, Text } from '@mantine/core';
|
||||
import { modalClasses } from 'styles';
|
||||
import SmallOutlookCard from './SmallOutlookCard';
|
||||
import SmallWeatherCard from './SmallWeatherCard';
|
||||
|
||||
import { useCommonHooks, useWeatherAPI } from 'hooks';
|
||||
import { useEffect, useState } from 'react';
|
||||
import HourlyCard from './HourlyCard';
|
||||
import {
|
||||
Area,
|
||||
CartesianGrid,
|
||||
ComposedChart,
|
||||
Legend,
|
||||
Line,
|
||||
ResponsiveContainer,
|
||||
Tooltip,
|
||||
XAxis,
|
||||
YAxis,
|
||||
} from 'recharts';
|
||||
import CurrentWeather from './CurrentWeather';
|
||||
import ExtendedForecast from './ExtendedForecast';
|
||||
|
||||
export function WeatherModal({
|
||||
current,
|
||||
outlook,
|
||||
extendedForecast,
|
||||
closeWeatherModal,
|
||||
weatherModalOpened,
|
||||
}: any) {
|
||||
@@ -31,9 +42,32 @@ export function WeatherModal({
|
||||
const [hourlyForecast, setHourlyForecast] = useState<any>([]);
|
||||
const [sunset, setSunset] = useState(100);
|
||||
|
||||
function CustomTooltip({ payload, active, unit }: any) {
|
||||
if (active) {
|
||||
return (
|
||||
<Stack
|
||||
style={{
|
||||
backgroundColor: 'var(--color-background)',
|
||||
padding: '1rem',
|
||||
borderRadius: '8px',
|
||||
}}
|
||||
>
|
||||
{payload.map((item: any) => (
|
||||
<Text
|
||||
key={item.name}
|
||||
size='sm'
|
||||
>{`${item.name} - ${item.value}${item.unit}`}</Text>
|
||||
))}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (hourly) {
|
||||
setHourlyForecast(hourly.properties.periods.slice(1, 13));
|
||||
setHourlyForecast(hourly.properties.periods.slice(1, 25));
|
||||
}
|
||||
}, [hourly]);
|
||||
|
||||
@@ -49,7 +83,6 @@ export function WeatherModal({
|
||||
);
|
||||
}
|
||||
}, [hourlyForecast]);
|
||||
|
||||
return (
|
||||
<Modal.Root
|
||||
fullScreen={isMobile}
|
||||
@@ -89,58 +122,99 @@ export function WeatherModal({
|
||||
</Modal.Title>
|
||||
<Modal.CloseButton />
|
||||
</Modal.Header>
|
||||
<Modal.Body pb={'2rem'}>
|
||||
<Modal.Body m={0}>
|
||||
<Center w={'100%'}>
|
||||
<Stack w={'100%'}>
|
||||
<Group gap={0} w={'100%'} align='center' justify='center'>
|
||||
<Stack gap={0} align='center'>
|
||||
<h3 style={{ padding: 0, margin: 0, color: 'white' }}>Currently</h3>
|
||||
<Stack>
|
||||
<SmallWeatherCard weather={current} />
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Divider
|
||||
orientation={isMobile ? 'horizontal' : 'vertical'}
|
||||
mx={16}
|
||||
color={theme.accentColor}
|
||||
/>
|
||||
<Group gap={8}>
|
||||
{outlook.map((o: any) => (
|
||||
<Stack key={o.name} gap={0} align='center'>
|
||||
<h3 style={{ padding: 0, margin: 0, color: 'white' }}>{o.name}</h3>
|
||||
<Stack>
|
||||
<SmallOutlookCard weather={o} />
|
||||
</Stack>
|
||||
</Stack>
|
||||
))}
|
||||
</Group>
|
||||
</Group>
|
||||
<Divider orientation='horizontal' mx={8} color={theme.accentColor} />
|
||||
<Group
|
||||
<CurrentWeather weather={current} />
|
||||
<Stack
|
||||
style={{
|
||||
background:
|
||||
hourlyForecast.length > 0 && hourlyForecast[0].isDaytime
|
||||
? `linear-gradient(90deg, rgba(245, 225, 171, 0.85) ${sunset - 5}%, rgba(35, 28, 42, 0.85) ${sunset + 5}%)`
|
||||
: `linear-gradient(90deg, rgba(35, 28, 42, 0.85)${sunset - 5}%, rgba(245, 225, 171, 0.85)${sunset + 5}%)`,
|
||||
background: 'var(--color-search-background)',
|
||||
padding: '.5rem',
|
||||
borderRadius: '.5rem',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
style={{
|
||||
display: 'flex',
|
||||
overflow: 'auto',
|
||||
whiteSpace: 'nowrap',
|
||||
justifyContent: 'space-between',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
{hourlyForecast.length > 0 &&
|
||||
hourlyForecast.map((h: any) => {
|
||||
return <HourlyCard key={h.number} weather={h} />;
|
||||
})}
|
||||
</Box>
|
||||
</Group>
|
||||
<ResponsiveContainer width={'100%'} height={150}>
|
||||
<ComposedChart data={hourlyForecast}>
|
||||
<XAxis
|
||||
type='category'
|
||||
stroke={theme.primaryColor}
|
||||
dataKey={(data: any) => {
|
||||
return new Date(data.startTime).toLocaleTimeString('en-US', {
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<YAxis
|
||||
stroke={theme.primaryColor}
|
||||
unit={'°F'}
|
||||
dataKey={'temperature'}
|
||||
/>
|
||||
<CartesianGrid stroke='#f5f5f522' />
|
||||
<Tooltip content={<CustomTooltip />} />
|
||||
<Line
|
||||
unit={'°F'}
|
||||
type='monotone'
|
||||
name='Temperature'
|
||||
dataKey='temperature'
|
||||
stroke={theme.primaryColor}
|
||||
dot={{ stroke: theme.primaryColor, strokeWidth: 1 }}
|
||||
/>
|
||||
<Line
|
||||
unit={'°F'}
|
||||
type='monotone'
|
||||
name='Dew Point'
|
||||
dataKey={(data: any) => {
|
||||
return (data.dewpoint.value * 9) / 5 + 32;
|
||||
}}
|
||||
stroke={theme.accentColor}
|
||||
dot={{ stroke: theme.primaryColor, strokeWidth: 1 }}
|
||||
/>
|
||||
<Legend style={{ background: 'var(--color-search-background)' }} />
|
||||
</ComposedChart>
|
||||
</ResponsiveContainer>
|
||||
<ResponsiveContainer width={'100%'} height={150}>
|
||||
<ComposedChart data={hourlyForecast}>
|
||||
<XAxis
|
||||
type='category'
|
||||
stroke={theme.primaryColor}
|
||||
dataKey={(data: any) => {
|
||||
return new Date(data.startTime).toLocaleTimeString('en-US', {
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<YAxis stroke={theme.primaryColor} unit={'%'} domain={[0, 100]} />
|
||||
<CartesianGrid stroke='#f5f5f522' />
|
||||
<Tooltip content={<CustomTooltip />} />
|
||||
<Area
|
||||
unit={'%'}
|
||||
type='monotone'
|
||||
name='Precipitation'
|
||||
dataKey={(data: any) => {
|
||||
return data.probabilityOfPrecipitation.value;
|
||||
}}
|
||||
stroke={theme.primaryColor}
|
||||
fill={theme.accentColor}
|
||||
dot={{ stroke: theme.primaryColor, strokeWidth: 1 }}
|
||||
/>
|
||||
<Area
|
||||
unit={'%'}
|
||||
type='monotone'
|
||||
name='Humidity'
|
||||
dataKey={(data: any) => {
|
||||
return data.relativeHumidity.value;
|
||||
}}
|
||||
stroke={theme.accentColor}
|
||||
fill={theme.accentColor}
|
||||
dot={{ stroke: theme.primaryColor, strokeWidth: 1 }}
|
||||
/>
|
||||
<Legend style={{ background: 'var(--color-search-background)' }} />
|
||||
</ComposedChart>
|
||||
</ResponsiveContainer>
|
||||
</Stack>
|
||||
<ExtendedForecast forecast={extendedForecast} />
|
||||
</Stack>
|
||||
</Center>
|
||||
</Modal.Body>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useCommonHooks, useOSMAPI, useQueryAPI, useWeatherAPI } from 'hooks';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { stackClasses } from 'styles';
|
||||
import type { CurrentWeather, OutlookWeather } from 'types';
|
||||
import type { ExtendedForecast } from 'types/weather';
|
||||
import Applications from './components/Applications/Applications';
|
||||
import Bookmarks from './components/Bookmarks/Bookmarks';
|
||||
import Header from './components/Header/Header';
|
||||
@@ -106,14 +107,17 @@ export function Homepage() {
|
||||
});
|
||||
const [current, setCurrent] = useState<CurrentWeather>({
|
||||
icon: '',
|
||||
textDescription: '',
|
||||
temperature: 0,
|
||||
highTemp: 0,
|
||||
lowTemp: 0,
|
||||
precipitation: 'N/A',
|
||||
humidity: 0,
|
||||
heatIndex: 0,
|
||||
heatIndex: null,
|
||||
windChill: null,
|
||||
windSpeed: 0,
|
||||
windDirection: 0,
|
||||
pressure: 0,
|
||||
});
|
||||
const [outlook, setOutlook] = useState<OutlookWeather[]>([
|
||||
{
|
||||
@@ -126,11 +130,22 @@ export function Homepage() {
|
||||
windDirection: 'N',
|
||||
},
|
||||
]);
|
||||
const [extendedForecast, setExtendedForecast] = useState<ExtendedForecast[]>([
|
||||
{
|
||||
detailedForecast: '',
|
||||
isDaytime: true,
|
||||
name: '',
|
||||
shortForecast: '',
|
||||
temperature: 0,
|
||||
temperatureUnit: 'F',
|
||||
},
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (weather !== undefined && basicWeather !== undefined) {
|
||||
setCurrent({
|
||||
icon: weather.features[0]?.properties.icon?.replace('medium', 'large') || '',
|
||||
textDescription: weather.features[0]?.properties.textDescription,
|
||||
temperature: Math.round(
|
||||
(weather.features[0]?.properties.temperature.value * 9) / 5 + 32,
|
||||
),
|
||||
@@ -143,13 +158,23 @@ export function Homepage() {
|
||||
precipitation:
|
||||
weather.features[0]?.properties.precipitationLastHour.value || 'N/A',
|
||||
humidity: Math.round(weather.features[0]?.properties.relativeHumidity.value),
|
||||
heatIndex: Math.round(
|
||||
weather.features[0]?.properties.heatIndex.value !== null
|
||||
? (weather.features[0]?.properties.heatIndex.value * 9) / 5 + 32
|
||||
: (weather.features[0]?.properties.temperature.value * 9) / 5 + 32,
|
||||
),
|
||||
heatIndex:
|
||||
basicWeather.properties.heatIndex?.values[0].value === null
|
||||
? null
|
||||
: Math.round(
|
||||
(basicWeather.properties.heatIndex.values[0].value * 9) / 5 + 32,
|
||||
),
|
||||
windChill:
|
||||
basicWeather.properties.windChill?.values[0].value === null
|
||||
? null
|
||||
: Math.round(
|
||||
(basicWeather.properties.windChill.values[0].value * 9) / 5 + 32,
|
||||
),
|
||||
windSpeed: Math.round(weather.features[0]?.properties.windSpeed.value / 1.60934),
|
||||
windDirection: weather.features[0]?.properties.windDirection.value,
|
||||
pressure: Math.round(
|
||||
weather.features[0]?.properties.barometricPressure.value / 3386.38,
|
||||
),
|
||||
});
|
||||
}
|
||||
}, [weather, basicWeather]);
|
||||
@@ -179,6 +204,16 @@ export function Homepage() {
|
||||
windDirection: forecast.properties.periods[1].windDirection,
|
||||
},
|
||||
]);
|
||||
setExtendedForecast(
|
||||
forecast.properties.periods.map((item: any) => ({
|
||||
detailedForecast: item.detailedForecast,
|
||||
isDaytime: item.isDaytime,
|
||||
name: item.name,
|
||||
shortForecast: item.shortForecast,
|
||||
temperature: item.temperature,
|
||||
temperatureUnit: item.temperatureUnit,
|
||||
})),
|
||||
);
|
||||
setCurrentLocation({
|
||||
office: points?.properties.gridId,
|
||||
station: stations?.features[0].properties.stationIdentifier,
|
||||
@@ -189,11 +224,13 @@ export function Homepage() {
|
||||
});
|
||||
}
|
||||
}, [forecast]);
|
||||
|
||||
return (
|
||||
<Stack gap={0} className={stackClasses.containerStack} justify='center'>
|
||||
<Search
|
||||
current={current}
|
||||
outlook={outlook}
|
||||
extendedForecast={extendedForecast}
|
||||
weather={weather}
|
||||
basicWeather={basicWeather}
|
||||
weatherModalOpened={weatherModalOpened}
|
||||
@@ -206,6 +243,7 @@ export function Homepage() {
|
||||
current={current}
|
||||
setCurrent={setCurrent}
|
||||
outlook={outlook}
|
||||
extendedForecast={extendedForecast}
|
||||
weather={weather}
|
||||
basicWeather={basicWeather}
|
||||
weatherModalOpened={weatherModalOpened}
|
||||
|
||||
@@ -10,6 +10,7 @@ function Header({
|
||||
current,
|
||||
setCurrent,
|
||||
outlook,
|
||||
extendedForecast,
|
||||
weather,
|
||||
basicWeather,
|
||||
weatherModalOpened,
|
||||
@@ -154,6 +155,7 @@ function Header({
|
||||
<WeatherModal
|
||||
current={current}
|
||||
outlook={outlook}
|
||||
extendedForecast={extendedForecast}
|
||||
closeWeatherModal={closeWeatherModal}
|
||||
weatherModalOpened={weatherModalOpened}
|
||||
/>
|
||||
|
||||
@@ -8,6 +8,7 @@ import { textInputClasses } from 'styles';
|
||||
export default function Search({
|
||||
current,
|
||||
outlook,
|
||||
extendedForecast,
|
||||
weatherModalOpened,
|
||||
closeWeatherModal,
|
||||
openWeatherModal,
|
||||
@@ -161,6 +162,7 @@ export default function Search({
|
||||
<WeatherModal
|
||||
current={current}
|
||||
outlook={outlook}
|
||||
extendedForecast={extendedForecast}
|
||||
closeWeatherModal={closeWeatherModal}
|
||||
weatherModalOpened={weatherModalOpened}
|
||||
/>
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
export interface CurrentWeather {
|
||||
icon: string;
|
||||
textDescription: string;
|
||||
temperature: number;
|
||||
highTemp: number;
|
||||
lowTemp: number;
|
||||
precipitation: string;
|
||||
humidity: number;
|
||||
heatIndex: number;
|
||||
heatIndex: number | null;
|
||||
windChill: number | null;
|
||||
windSpeed: number;
|
||||
windDirection: number;
|
||||
pressure: number;
|
||||
}
|
||||
|
||||
export interface OutlookWeather {
|
||||
@@ -19,3 +22,12 @@ export interface OutlookWeather {
|
||||
windSpeed: string;
|
||||
windDirection: string;
|
||||
}
|
||||
|
||||
export interface ExtendedForecast {
|
||||
detailedForecast: string;
|
||||
isDaytime: boolean;
|
||||
name: string;
|
||||
shortForecast: string;
|
||||
temperature: number;
|
||||
temperatureUnit: string;
|
||||
}
|
||||
|
||||