simple website with default airports

This commit is contained in:
2023-08-24 10:00:40 -04:00
parent cb005a1b98
commit 08bcce3813
31 changed files with 9244 additions and 855 deletions

35
.eslintrc.json Executable file
View File

@@ -0,0 +1,35 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": [
// "@typescript-eslint",
// "prettier"
],
"extends": [
// "prettier",
// "eslint:recommended",
// "next/core-web-vitals",
// "plugin:import/typescript",
// "plugin:prettier/recommended",
// "plugin:react/recommended",
// "plugin:@typescript-eslint/recommended",
// "plugin:@typescript-eslint/eslint-recommended",
// "plugin:@typescript-eslint/recommended-requiring-type-checking"
],
"rules": {
"react-hooks/rules-of-hooks": "off", // error
"react-hooks/exhaustive-deps": "off",
"prettier/prettier": "off"
},
"overrides": [
{
"files": ["*.ts", "*.tsx"],
"extends": [
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking"
],
"parserOptions": {
"project": ["./tsconfig.json"]
}
}]
}

39
.gitignore vendored
View File

@@ -1,3 +1,38 @@
/target/ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
.env # dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
/target/
/dist/

7
.prettierrc.json Normal file
View File

@@ -0,0 +1,7 @@
{
"trailingComma": "es5",
"tabWidth": 4,
"semi": true,
"singleQuote": true,
"printWidth": 100
}

696
Cargo.lock generated
View File

@@ -4,9 +4,9 @@ version = 3
[[package]] [[package]]
name = "addr2line" name = "addr2line"
version = "0.20.0" version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
dependencies = [ dependencies = [
"gimli", "gimli",
] ]
@@ -26,12 +26,6 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "anyhow"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@@ -42,19 +36,20 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
name = "aviation-weather" name = "aviation-weather"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"dotenv",
"env_logger", "env_logger",
"gtk4",
"log", "log",
"regex", "quick-xml",
"reqwest", "reqwest",
"serde",
"tokio", "tokio",
] ]
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.68" version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
dependencies = [ dependencies = [
"addr2line", "addr2line",
"cc", "cc",
@@ -95,31 +90,6 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
[[package]]
name = "cairo-rs"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d859b656775a6b1dd078d3e5924884e6ea88aa649a7fdde03d5b2ec56ffcc10b"
dependencies = [
"bitflags 2.4.0",
"cairo-sys-rs",
"glib",
"libc",
"once_cell",
"thiserror",
]
[[package]]
name = "cairo-sys-rs"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd4d115132e01c0165e3bf5f56aedee8980b0b96ede4eb000b693c05a8adb8ff"
dependencies = [
"glib-sys",
"libc",
"system-deps",
]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.83" version = "1.0.83"
@@ -129,16 +99,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "cfg-expr"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b40ccee03b5175c18cde8f37e7d2a33bcef6f8ec8f7cc0d81090d1bb380949c9"
dependencies = [
"smallvec",
"target-lexicon",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
@@ -161,6 +121,12 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
[[package]]
name = "dotenv"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
version = "0.8.32" version = "0.8.32"
@@ -183,12 +149,6 @@ dependencies = [
"termcolor", "termcolor",
] ]
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.2" version = "0.3.2"
@@ -216,16 +176,6 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
[[package]]
name = "field-offset"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f"
dependencies = [
"memoffset",
"rustc_version",
]
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@@ -271,34 +221,6 @@ version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
[[package]]
name = "futures-executor"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
[[package]]
name = "futures-macro"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.29",
]
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.28" version = "0.3.28"
@@ -318,274 +240,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-macro",
"futures-task", "futures-task",
"pin-project-lite", "pin-project-lite",
"pin-utils", "pin-utils",
"slab",
]
[[package]]
name = "gdk-pixbuf"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbc9c2ed73a81d556b65d08879ba4ee58808a6b1927ce915262185d6d547c6f3"
dependencies = [
"gdk-pixbuf-sys",
"gio",
"glib",
"libc",
"once_cell",
]
[[package]]
name = "gdk-pixbuf-sys"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7"
dependencies = [
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
]
[[package]]
name = "gdk4"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6982d9815ed6ac95b0467b189e81f29dea26d08a732926ec113e65744ed3f96c"
dependencies = [
"cairo-rs",
"gdk-pixbuf",
"gdk4-sys",
"gio",
"glib",
"libc",
"pango",
]
[[package]]
name = "gdk4-sys"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbab43f332a3cf1df9974da690b5bb0e26720ed09a228178ce52175372dcfef0"
dependencies = [
"cairo-sys-rs",
"gdk-pixbuf-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"pango-sys",
"pkg-config",
"system-deps",
] ]
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.27.3" version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
[[package]]
name = "gio"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7884cba6b1c5db1607d970cadf44b14a43913d42bc68766eea6a5e2fe0891524"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-util",
"gio-sys",
"glib",
"libc",
"once_cell",
"pin-project-lite",
"smallvec",
"thiserror",
]
[[package]]
name = "gio-sys"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
"winapi",
]
[[package]]
name = "glib"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "331156127e8166dd815cf8d2db3a5beb492610c716c03ee6db4f2d07092af0a7"
dependencies = [
"bitflags 2.4.0",
"futures-channel",
"futures-core",
"futures-executor",
"futures-task",
"futures-util",
"gio-sys",
"glib-macros",
"glib-sys",
"gobject-sys",
"libc",
"memchr",
"once_cell",
"smallvec",
"thiserror",
]
[[package]]
name = "glib-macros"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "179643c50bf28d20d2f6eacd2531a88f2f5d9747dd0b86b8af1e8bb5dd0de3c0"
dependencies = [
"heck",
"proc-macro-crate",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.29",
]
[[package]]
name = "glib-sys"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898"
dependencies = [
"libc",
"system-deps",
]
[[package]]
name = "gobject-sys"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44"
dependencies = [
"glib-sys",
"libc",
"system-deps",
]
[[package]]
name = "graphene-rs"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2228cda1505613a7a956cca69076892cfbda84fc2b7a62b94a41a272c0c401"
dependencies = [
"glib",
"graphene-sys",
"libc",
]
[[package]]
name = "graphene-sys"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc4144cee8fc8788f2a9b73dc5f1d4e1189d1f95305c4cb7bd9c1af1cfa31f59"
dependencies = [
"glib-sys",
"libc",
"pkg-config",
"system-deps",
]
[[package]]
name = "gsk4"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc25855255120f294d874acd6eaf4fbed7ce1cdc550e2d8415ea57fafbe816d5"
dependencies = [
"cairo-rs",
"gdk4",
"glib",
"graphene-rs",
"gsk4-sys",
"libc",
"pango",
]
[[package]]
name = "gsk4-sys"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1ecf3a63bf1223d68f80f72cc896c4d8c80482fbce1c9a12c66d3de7290ee46"
dependencies = [
"cairo-sys-rs",
"gdk4-sys",
"glib-sys",
"gobject-sys",
"graphene-sys",
"libc",
"pango-sys",
"system-deps",
]
[[package]]
name = "gtk4"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3b095b26f2a2df70be1805d3590eeb9d7a05ecb5be9649b82defc72dc56228c"
dependencies = [
"cairo-rs",
"field-offset",
"futures-channel",
"gdk-pixbuf",
"gdk4",
"gio",
"glib",
"graphene-rs",
"gsk4",
"gtk4-macros",
"gtk4-sys",
"libc",
"pango",
]
[[package]]
name = "gtk4-macros"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d57ec49cf9b657f69a05bca8027cff0a8dfd0c49e812be026fc7311f2163832f"
dependencies = [
"anyhow",
"proc-macro-crate",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "gtk4-sys"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b0bdde87c50317b4f355bcbb4a9c2c414ece1b7c824fb4ad4ba8f3bdb2c6603"
dependencies = [
"cairo-sys-rs",
"gdk-pixbuf-sys",
"gdk4-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"graphene-sys",
"gsk4-sys",
"libc",
"pango-sys",
"system-deps",
]
[[package]] [[package]]
name = "h2" name = "h2"
@@ -599,7 +263,7 @@ dependencies = [
"futures-sink", "futures-sink",
"futures-util", "futures-util",
"http", "http",
"indexmap 1.9.3", "indexmap",
"slab", "slab",
"tokio", "tokio",
"tokio-util", "tokio-util",
@@ -612,18 +276,6 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.3.2" version = "0.3.2"
@@ -724,17 +376,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown 0.12.3", "hashbrown",
]
[[package]]
name = "indexmap"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
dependencies = [
"equivalent",
"hashbrown 0.14.0",
] ]
[[package]] [[package]]
@@ -787,16 +429,6 @@ version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
[[package]]
name = "lock_api"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.20" version = "0.4.20"
@@ -809,15 +441,6 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memoffset"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "mime" name = "mime"
version = "0.3.17" version = "0.3.17"
@@ -862,21 +485,11 @@ dependencies = [
"tempfile", "tempfile",
] ]
[[package]]
name = "num_cpus"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
"hermit-abi",
"libc",
]
[[package]] [[package]]
name = "object" name = "object"
version = "0.31.1" version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@@ -910,7 +523,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.29", "syn",
] ]
[[package]] [[package]]
@@ -931,54 +544,6 @@ dependencies = [
"vcpkg", "vcpkg",
] ]
[[package]]
name = "pango"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06a9e54b831d033206160096b825f2070cf5fda7e35167b1c01e9e774f9202d1"
dependencies = [
"gio",
"glib",
"libc",
"once_cell",
"pango-sys",
]
[[package]]
name = "pango-sys"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
]
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets",
]
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.3.0" version = "2.3.0"
@@ -1003,40 +568,6 @@ version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "proc-macro-crate"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
dependencies = [
"once_cell",
"toml_edit",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn 1.0.109",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.66" version = "1.0.66"
@@ -1046,6 +577,16 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "quick-xml"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956"
dependencies = [
"memchr",
"serde",
]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.33" version = "1.0.33"
@@ -1136,15 +677,6 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver",
]
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.8" version = "0.38.8"
@@ -1173,12 +705,6 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]] [[package]]
name = "security-framework" name = "security-framework"
version = "2.9.2" version = "2.9.2"
@@ -1202,17 +728,25 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "semver"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.185" version = "1.0.185"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be9b6f69f1dfd54c3b568ffa45c310d6973a5e5148fd40cf515acaf38cf5bc31" checksum = "be9b6f69f1dfd54c3b568ffa45c310d6973a5e5148fd40cf515acaf38cf5bc31"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.185"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc59dfdcbad1437773485e0367fea4b090a2e0a16d9ffc46af47764536a298ec"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
@@ -1225,15 +759,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_spanned"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "serde_urlencoded" name = "serde_urlencoded"
version = "0.7.1" version = "0.7.1"
@@ -1246,30 +771,15 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.8" version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "smallvec"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.4.9" version = "0.4.9"
@@ -1290,17 +800,6 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.29" version = "2.0.29"
@@ -1312,25 +811,6 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "system-deps"
version = "6.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30c2de8a4d8f4b823d634affc9cd2a74ec98c53a756f317e529a48046cbf71f3"
dependencies = [
"cfg-expr",
"heck",
"pkg-config",
"toml",
"version-compare",
]
[[package]]
name = "target-lexicon"
version = "0.12.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a"
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.8.0" version = "3.8.0"
@@ -1353,26 +833,6 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "thiserror"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.29",
]
[[package]] [[package]]
name = "tinyvec" name = "tinyvec"
version = "1.6.0" version = "1.6.0"
@@ -1398,10 +858,7 @@ dependencies = [
"bytes", "bytes",
"libc", "libc",
"mio", "mio",
"num_cpus",
"parking_lot",
"pin-project-lite", "pin-project-lite",
"signal-hook-registry",
"socket2 0.5.3", "socket2 0.5.3",
"tokio-macros", "tokio-macros",
"windows-sys", "windows-sys",
@@ -1415,7 +872,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.29", "syn",
] ]
[[package]] [[package]]
@@ -1442,40 +899,6 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "toml"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.19.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a"
dependencies = [
"indexmap 2.0.0",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
[[package]] [[package]]
name = "tower-service" name = "tower-service"
version = "0.3.2" version = "0.3.2"
@@ -1546,18 +969,6 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version-compare"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "want" name = "want"
version = "0.3.1" version = "0.3.1"
@@ -1594,7 +1005,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.29", "syn",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@@ -1628,7 +1039,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.29", "syn",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@@ -1746,15 +1157,6 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "winnow"
version = "0.5.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d09770118a7eb1ccaf4a594a221334119a44a814fcb0d31c5b85e83e97227a97"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "winreg" name = "winreg"
version = "0.50.0" version = "0.50.0"

View File

@@ -6,9 +6,10 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
dotenv = "0.15.0"
env_logger = "0.10.0" env_logger = "0.10.0"
gtk = { version = "0.7.2", package = "gtk4", features = ["v4_12"] }
log = "0.4.20" log = "0.4.20"
regex = "1.9.3" quick-xml = { version = "0.30.0", features = ["serialize"] }
reqwest = "0.11.19" reqwest = "0.11.19"
tokio = { version = "1.32.0", features = ["full"] } serde = {version = "1.0.185", features = ["derive"]}
tokio = { version = "1.32.0", features = ["macros", "rt"] }

25
Makefile Normal file
View File

@@ -0,0 +1,25 @@
#!make
SHELL := /bin/bash
.PHONY: help build start stop lint
help: ## This info
@echo
@cat Makefile | grep -E '^[a-zA-Z\/_-]+:.*?## .*$$' | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
@echo
install: ## Install the dependencies
npm install
build: ## Install the dependencies and build
npm run build
start: ## Start the dev instance
npm run dev
lint: ## Run the linter
npm run lint
clean: ## Remove node modules
rm -rf node_modules

25
README.md Normal file → Executable file
View File

@@ -1,3 +1,24 @@
# Aviation Weather # PCS UI
`cargo run` # Getting Started
The main installed packages are the following:
- [Next.js](https://nextjs.org/docs)
- [ESLint](https://eslint.org/docs/latest/rules/)
- [Typescript](https://www.typescriptlang.org/docs/)
ESLint rules can be configured in the `.eslintrc.json` file.
Prettier rules can be configured in the `.prettierrc.json` file.
TypeScript rules can be configured in the `.tsconfig.json` file.
Next.js (React Framework)
- [Next.js Project Structure](https://nextjs.org/docs/getting-started/project-structure)
- [Next.js App Routing](https://nextjs.org/docs/app/building-your-application/routing)
- [Next.js Pages Routing](https://nextjs.org/docs/pages/building-your-application/routing)
Redux
- [Getting Started](https://redux.js.org/introduction/getting-started)
- [Code Structure](https://redux.js.org/faq/code-structure)
- [React Redux](https://redux.js.org/faq/react-redux)
## Makefile
`make help` to list all commands

5
next-env.d.ts vendored Executable file
View File

@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

10
next.config.js Executable file
View File

@@ -0,0 +1,10 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
experimental: {
serverActions: true,
},
}
module.exports = nextConfig

8400
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

35
package.json Normal file
View File

@@ -0,0 +1,35 @@
{
"name": "pcs-ui",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"axios": "^1.4.0",
"next": "13.4.12",
"react": "18.2.0",
"react-dom": "18.2.0",
"recoil": "^0.7.7",
"xml-js": "^1.6.11"
},
"devDependencies": {
"@types/node": "20.4.5",
"@types/react": "18.2.16",
"@types/react-dom": "18.2.7",
"@typescript-eslint/eslint-plugin": "^6.2.0",
"@typescript-eslint/parser": "^6.2.0",
"autoprefixer": "^10.4.15",
"eslint": "8.45.0",
"eslint-config-next": "13.4.12",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
"postcss": "^8.4.28",
"prettier": "^3.0.0",
"tailwindcss": "^3.3.3",
"typescript": "5.1.6"
}
}

6
postcss.config.js Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

BIN
public/favicon.ico Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

4
public/vercel.svg Executable file
View File

@@ -0,0 +1,4 @@
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,10 +0,0 @@
pub struct Airport {
pub name: String,
pub icao: String
}
impl Airport {
pub fn new(name: String, icao: String) -> Airport {
Airport { name, icao }
}
}

View File

View File

@@ -0,0 +1,49 @@
import { Airport } from "@/js/airport";
import { Metar, getMetars } from "@/js/weather"
import Link from "next/link"
export default async function MetarCard({airports}: {airports: Airport[]}) {
// await getMetars(defaultAirports).then((result) => {
// setMetars(result);
// });
const metars = await getMetars(airports);
for (let i = 0; i < airports.length; i++) {
airports[i].metar = metars[i];
}
function metarBGColor(metar: Metar | undefined) {
if (metar?.flight_category == 'VFR') {
return 'bg-emerald-600'
} else if (metar?.flight_category == 'MVFR') {
return 'bg-blue-600'
} else if (metar?.flight_category == 'IFR') {
return 'bg-red-600'
} else if (metar?.flight_category == 'LIFR') {
return 'bg-purple-600'
} else {
return 'bg-black'
}
}
return (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
{airports.map((airport) => (
<div
key={airport.metar?.station_id}
className={`relative flex items-center space-x-3 rounded-lg border border-gray-300 bg-white px-4 py-2 shadow-sm focus-within:ring-2 focus-within:ring-indigo-500 focus-within:ring-offset-2 hover:border-gray-400`}
>
<div className="min-w-0 flex-1">
<Link href={'#'}>
<span className="absolute inset-0" aria-hidden="true" />
<p className="text-gray-900 pb-1">{airport.metar?.station_id} - <span>{airport.name}</span></p>
<p className='text-sm font-medium text-gray-500'>{airport.metar?.raw_text}</p>
<div className='mt-2'>
<span className={`truncate text-sm text-white ${metarBGColor(airport.metar)} inline-block py-2 px-4 rounded-full`}>{airport.metar?.flight_category}</span>
</div>
</Link>
</div>
</div>
))}
</div>
)
}

14
src/app/layout.tsx Normal file
View File

@@ -0,0 +1,14 @@
import React from 'react';
import RecoilRootWrapper from '@app/recoil-root-wrapper';
import 'styles/globals.css';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body className='bg-gray-200'>
<RecoilRootWrapper>{children}</RecoilRootWrapper>
</body>
</html>
);
}

55
src/app/page.tsx Normal file
View File

@@ -0,0 +1,55 @@
// 'use client';
import { Airport } from '@/js/airport';
import React from 'react';
import MetarCard from './components/MetarCard';
export default function Page() {
// const [airports, setAirports] = useRecoilState(airportsState);
// useEffect(() => {
// const defaultAirports = [
// new Airport('Leesburg Executive Airport', 'KJYO'),
// new Airport('Manassas Regional Airpoirt', 'KHEF'),
// new Airport('Dulles International Airport', 'KIAD'),
// new Airport('Frederick Municipal Airport', 'KFDK'),
// new Airport('Eastern West Virginia Regional Airport', 'KMRB'),
// new Airport('Winchester Regional Airport', 'KOKV'),
// new Airport('Front Royal-Warren County Airport', 'KFRR'),
// new Airport('Luray Caverns Airport', 'KLUA'),
// new Airport('Shenandoah Valley Airport', 'KSHD'),
// new Airport('Charlottesville-Albemarle Airport', 'KCHO'),
// new Airport('Culpeper Regional Airport', 'KCJR'),
// new Airport('Warrenton-Fauquier Airport', 'KHWY'),
// new Airport('Stafford Regional Airport', 'KRMN'),
// new Airport('Shannon Airport', 'KEZF'),
// ];
// setAirports(defaultAirports);
// }, []);
const defaultAirports = [
new Airport('Leesburg Executive Airport', 'KJYO'),
new Airport('Manassas Regional Airpoirt', 'KHEF'),
new Airport('Dulles International Airport', 'KIAD'),
new Airport('Frederick Municipal Airport', 'KFDK'),
new Airport('Eastern West Virginia Regional Airport', 'KMRB'),
new Airport('Winchester Regional Airport', 'KOKV'),
new Airport('Front Royal-Warren County Airport', 'KFRR'),
new Airport('Luray Caverns Airport', 'KLUA'),
new Airport('Shenandoah Valley Airport', 'KSHD'),
new Airport('Charlottesville-Albemarle Airport', 'KCHO'),
new Airport('Culpeper Regional Airport', 'KCJR'),
new Airport('Warrenton-Fauquier Airport', 'KHWY'),
new Airport('Stafford Regional Airport', 'KRMN'),
new Airport('Shannon Airport', 'KEZF'),
];
return <>
<div className="border-b border-gray-200 bg-gray-400 px-4 py-5 sm:px-6">
<h3 className="text-base font-semibold leading-6 text-gray-900">Airports</h3>
</div>
<div className='p-4'>
<MetarCard airports={defaultAirports}/>
</div>
</>;
}

View File

@@ -0,0 +1,10 @@
'use client';
import { RecoilRoot } from 'recoil';
import React, { ReactNode } from 'react';
const RecoilRootWrapper = ({ children }: { children: ReactNode }) => (
<RecoilRoot>{children}</RecoilRoot>
);
export default RecoilRootWrapper;

13
src/js/airport.ts Normal file
View File

@@ -0,0 +1,13 @@
import { Metar } from "./weather";
export class Airport {
name: string;
icao: string;
metar: Metar | undefined;
constructor(name: string, icao: string) {
this.name = name;
this.icao = icao;
this.metar = undefined;
}
}

7
src/js/state.ts Normal file
View File

@@ -0,0 +1,7 @@
import { atom } from "recoil";
import { Airport } from "./airport";
export const airportsState = atom({
key: 'airportsState',
default: [] as Airport[]
});

104
src/js/weather.ts Normal file
View File

@@ -0,0 +1,104 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import axios from 'axios';
import { xml2json } from 'xml-js';
import { Airport } from './airport';
const base_url = 'https://beta.aviationweather.gov/cgi-bin/data';
export async function getMetars(airports: Airport[]): Promise<Metar[]> {
const stationICAOs: string = airports
.map((airport) => airport.icao)
.join(',');
const url = `${base_url}/metar.php?ids=${stationICAOs}&format=xml`;
const response = await axios
.get(`${url}`)
.catch((error) => console.error(`${error}`));
// const metars = new Map<string, Metar>();
const metars: Metar[] = [];
if (response != null && response != undefined) {
const json = xml2json(response.data, { compact: true });
const jsonObject = JSON.parse(json);
const metarData = jsonObject?.response?.data?.METAR;
for (const data of metarData) {
const sky_condition: {
sky_cover: string;
cloud_base_ft_agl: number;
}[] = [];
if (Array.isArray(data.sky_condition)) {
for (const sc of data.sky_condition) {
sky_condition.push({
sky_cover: sc.sky_cover,
cloud_base_ft_agl: Number(sc.cloud_base_ft_agl)
})
}
} else {
sky_condition.push({
sky_cover: data.sky_condition?.sky_cover,
cloud_base_ft_agl: Number(data.sky_condition?.cloud_base_ft_agl)
})
}
const metar: Metar = {
raw_text: data.raw_text._text,
station_id: data.station_id._text,
observation_time: data.observation_time._text,
latitude: Number(data.latitude._text),
longitude: Number(data.longitude._text),
temp_c: Number(data.temp_c._text),
dewpoint_c: Number(data.dewpoint_c._text),
wind_dir_degrees: Number(data.wind_dir_degrees._text),
wind_speed_kt: Number(data.wind_speed_kt._text),
visibility_statute_mi: data.visibility_statute_mi._text,
altim_in_hg: Number(data.altim_in_hg._text),
sea_level_pressure_mb: data.sea_level_pressure_mb?._text,
quality_control_flags: {
auto: data.quality_control_flags?.auto?._text == 'TRUE',
auto_station: data.quality_control_flags?.auto_station?._text == 'TRUE',
},
wx_string: data.wx_string?._text,
sky_condition: sky_condition,
flight_category: data.flight_category._text,
three_hr_pressure_tendency_mb: data.three_hr_pressure_tendency_mb?._text,
metar_type: data.metar_type._text,
maxT_c: Number(data.maxT_c?._text),
minT_c: Number(data.minT_c?._text),
precip_in: Number(data.precip_in?._text),
elevation_m: Number(data.elevation_m._text),
};
metars.push(metar);
}
}
return metars;
}
export interface Metar {
raw_text: string;
station_id: string;
observation_time: string;
latitude: number;
longitude: number;
temp_c: number;
dewpoint_c: number;
wind_dir_degrees: number;
wind_speed_kt: number;
visibility_statute_mi: string;
altim_in_hg: number;
sea_level_pressure_mb: number;
quality_control_flags: {
auto: boolean;
auto_station: boolean;
};
wx_string: string;
sky_condition: {
sky_cover: string;
cloud_base_ft_agl: number;
}[];
flight_category: string;
three_hr_pressure_tendency_mb: number;
metar_type: string;
maxT_c: number;
minT_c: number;
precip_in: number;
elevation_m: number;
}

162
src/lib.rs Normal file
View File

@@ -0,0 +1,162 @@
use std::error::Error;
use std::fmt;
use log::warn;
use std::io::BufRead;
use quick_xml::{Reader, events::{Event, BytesStart}, Writer, de::Deserializer};
use serde::Deserialize;
pub struct Airport {
pub name: String,
pub icao: String
}
impl Airport {
pub fn new(name: String, icao: String) -> Airport {
Airport { name, icao }
}
}
#[derive(Debug)]
pub struct WeatherError(pub String);
impl fmt::Display for WeatherError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl Error for WeatherError {}
#[derive(Deserialize, Debug)]
pub struct Metar {
pub raw_text: String,
pub station_id: String,
pub observation_time: String,
pub latitude: f32,
pub longitude: f32,
pub temp_c: f32,
pub dewpoint_c: f32,
pub wind_dir_degrees: i32,
pub wind_speed_kt: i32,
pub visibility_statute_mi: String,
pub altim_in_hg: f32,
pub sea_level_pressure_mb: Option<f32>,
pub quality_control_flags: Option<QualityControlFlags>,
pub wx_string: Option<String>,
// pub sky_con dition: Option<Vec<String>>, // TODO work on attributes
pub flight_category: String,
pub three_hr_pressure_tendency_mb: Option<f32>,
pub metar_type: String,
#[serde(rename = "maxT_c")]
pub max_t_c: Option<f32>,
#[serde(rename = "minT_c")]
pub min_t_c: Option<f32>,
pub precip_in: Option<f32>,
pub elevation_m: i32
}
#[derive(Deserialize, Debug)]
pub struct QualityControlFlags {
pub auto: Option<bool>,
pub auto_station: Option<bool>
}
impl Metar {
pub fn parse(input: String) -> Result<Vec<Metar>, WeatherError> {
if input.is_empty() {
return Err(WeatherError("Input is empty".to_string()))
}
let mut reader = Reader::from_str(&input);
let mut buf = Vec::new();
let mut junk_buf: Vec<u8> = Vec::new();
loop {
match reader.read_event_into(&mut buf) {
Err(e) => panic!("Error at position: {}: {:?}", reader.buffer_position(), e),
Ok(Event::Eof) => break,
Ok(Event::Start(e)) => {
match e.name().as_ref() {
b"METAR" => {
let metar_bytes = Metar::read_to_end_into_buffer(&mut reader, &e, &mut junk_buf).unwrap();
let str = std::str::from_utf8(&metar_bytes).unwrap();
let mut deserializer = Deserializer::from_str(str);
let metar = Metar::deserialize(&mut deserializer).unwrap();
println!("{:#?}", metar);
},
_ => ()
}
},
_ => ()
}
}
return Ok(vec![])
}
// https://capnfabs.net/posts/parsing-huge-xml-quickxml-rust-serde/
pub fn read_to_end_into_buffer<R: BufRead>(reader: &mut Reader<R>, start_tag: &BytesStart, junk_buf: &mut Vec<u8>) -> Result<Vec<u8>, quick_xml::Error> {
let mut depth = 0;
let mut output_buf: Vec<u8> = Vec::new();
let mut w = Writer::new(&mut output_buf);
let tag_name = start_tag.name();
w.write_event(Event::Start(start_tag.clone()))?;
loop {
junk_buf.clear();
let event = reader.read_event_into(junk_buf)?;
w.write_event(&event)?;
match event {
Event::Start(e) if e.name() == tag_name => depth += 1,
Event::End(e) if e.name() == tag_name => {
if depth == 0 {
return Ok(output_buf);
}
depth -= 1;
}
Event::Eof => {
panic!("EOF")
}
_ => {}
}
}
}
}
pub struct Weather {
pub base_url: String
}
impl Weather {
pub async fn metar(&mut self, airports: Vec<Airport>) -> Vec<Metar> {
let mut station_icaos: Vec<&str> = vec![];
for station in airports.iter() {
station_icaos.push(&station.icao);
}
let station_string = station_icaos.join(",");
let url = format!("{}/metar.php?ids={}&format=xml", self.base_url, station_string);
let metars: Vec<Metar> = match reqwest::get(url).await {
Ok(r) => match r.text().await {
Ok(r) => {
match Metar::parse(r) {
Ok(m) => m,
Err(err) => {
warn!("{}", err);
vec![]
}
}
},
Err(err) => {
warn!("Unable to parse METAR request: {}", err);
vec![]
}
},
Err(err) => {
warn!("Unable to get METAR request: {}", err);
vec![]
}
};
return metars;
}
}

View File

@@ -1,37 +0,0 @@
use std::error::Error;
use airport::Airport;
use log::debug;
use crate::weather::{Weather, metar::Metar};
mod airport;
mod weather;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
let mut weather = Weather {
base_url: "https://beta.aviationweather.gov/cgi-bin/data".to_string()
};
let airports: Vec<Airport> = vec![
Airport::new("Leesburg Executive Airport".to_string(), "KJYO".to_string()),
Airport::new("Manassas Regional Airpoirt".to_string(), "KHEF".to_string()),
Airport::new("Dulles International Airport".to_string(), "KIAD".to_string()),
Airport::new("Frederick Municipal Airport".to_string(), "KFDK".to_string()),
Airport::new("Eastern West Virginia Regional Airport".to_string(), "KMRB".to_string()),
Airport::new("Winchester Regional Airport".to_string(), "KOKV".to_string()),
Airport::new("Front Royal-Warren County Airport".to_string(), "KFRR".to_string()),
Airport::new("Luray Caverns Airport".to_string(), "KLUA".to_string()),
Airport::new("Shenandoah Valley Airport".to_string(), "KSHD".to_string()),
Airport::new("Charlottesville-Albemarle Airport".to_string(), "KCHO".to_string()),
Airport::new("Culpeper Regional Airport".to_string(), "KCJR".to_string()),
Airport::new("Warrenton-Fauquier Airport".to_string(), "KHWY".to_string()),
Airport::new("Stafford Regional Airport".to_string(), "KRMN".to_string()),
Airport::new("Shannon Airport".to_string(), "KEZF".to_string()),
];
let metars: Vec<Metar> = weather.metar(airports).await;
debug!("{:#?}", metars);
Ok(())
}

View File

@@ -1,102 +0,0 @@
use regex::Regex;
use super::WeatherError;
#[derive(Debug)]
pub struct Metar {
pub icao: String,
pub date_time: String,
pub report_modifier: String,
pub wind_direction: String,
pub wind_speed: String,
pub wind_direction_variable: String,
pub visibility: String,
pub runway_visual_range: String,
pub weather_phenomena: Vec<String>,
pub sky_condition: Vec<String>,
pub temperature: String,
pub dew_point: String,
pub altimeter: String,
pub remarks: Vec<String>
}
impl Metar {
pub fn new(input: String) -> Result<Metar, WeatherError> {
if input.is_empty() {
return Err(WeatherError("Input is empty".to_string()))
}
let mut offset: usize = 0;
let parts: Vec<&str> = input.split_whitespace().collect();
if parts.len() < 5 {
return Err(WeatherError("Unable to parse input".to_string()))
}
let mut report_modifier = "";
if parts[2] == "AUTO" {
offset += 1;
report_modifier = parts[2];
}
let wind_re = Regex::new(r"^\d{3}V\d{3}$").unwrap();
let wind_direction_variable = match wind_re.find(parts[3 + offset]) {
Some(_) => {
offset += 1;
parts[3 + offset]
},
None => ""
};
let mut runway_visual_range = "";
if parts[4 + offset].ends_with("FT") {
offset += 1;
runway_visual_range = parts[4 + offset];
}
let mut weather_phenomena: Vec<String> = vec![];
let weather_re = Regex::new(r"^(-|\+)?[A-Z]{2}(?:[A-Z]{2})?$").unwrap();
let mut sky_condition: Vec<String> = vec![];
let sky_re = Regex::new(r"^CLR|(FEW|SCT|BKN|OVC)\d{3}$").unwrap();
for n in (4 + offset)..parts.len() {
match weather_re.find(parts[n]) {
Some(_) => {
offset += 1;
weather_phenomena.push(parts[n].to_string());
},
None => {}
}
match sky_re.find(parts[n]) {
Some(_) => {
offset += 1;
sky_condition.push(parts[n].to_string());
},
None => {}
}
}
let temp_dew: Vec<&str> = parts[4 + offset].split("/").collect();
let mut remarks: Vec<String> = vec![];
if parts.len() > 6 + offset {
// Skip the RMK string for remarks, starting at index + 1
for n in (6 + offset + 1)..parts.len() {
remarks.push(parts[n].to_string())
}
}
Ok(Metar {
icao: parts[0].to_string(),
date_time: parts[1].to_string(),
report_modifier: report_modifier.to_string(),
wind_direction: parts[2 + offset][..3].to_string(),
wind_speed: parts[2 + offset][3..].to_string(),
wind_direction_variable: wind_direction_variable.to_string(),
visibility: parts[3 + offset].to_string(),
runway_visual_range: runway_visual_range.to_string(),
weather_phenomena,
sky_condition,
temperature: temp_dew[0].to_string(),
dew_point: temp_dew[1].to_string(),
altimeter: parts[5 + offset].to_string(),
remarks
})
}
}

View File

@@ -1,52 +0,0 @@
use std::error::Error;
use std::fmt;
use log::warn;
use crate::airport::Airport;
use self::metar::Metar;
pub mod metar;
#[derive(Debug)]
pub struct WeatherError(pub String);
impl fmt::Display for WeatherError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl Error for WeatherError {}
pub struct Weather {
pub base_url: String
}
impl Weather {
pub async fn metar(&mut self, airports: Vec<Airport>) -> Vec<Metar> {
let mut station_icaos: Vec<&str> = vec![];
for station in airports.iter() {
station_icaos.push(&station.icao);
}
let station_string = station_icaos.join(",");
let url = format!("{}/metar.php?ids={}", self.base_url, station_string);
let mut metars: Vec<Metar> = vec![];
match reqwest::get(url).await {
Ok(r) => match r.text().await {
Ok(r) => {
let lines: Vec<&str> = r.split("\n").collect();
for line in lines.iter() {
match Metar::new(line.to_string()) {
Ok(m) => metars.push(m),
Err(err) => warn!("{}", err)
};
}
},
Err(err) => warn!("Unable to parse METAR request: {}", err)
},
Err(err) => warn!("Unable to get METAR request: {}", err)
}
return metars;
}
}

116
styles/Home.module.css Executable file
View File

@@ -0,0 +1,116 @@
.container {
padding: 0 2rem;
}
.main {
min-height: 100vh;
padding: 4rem 0;
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.footer {
display: flex;
flex: 1;
padding: 2rem 0;
border-top: 1px solid #eaeaea;
justify-content: center;
align-items: center;
}
.footer a {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
}
.title a {
color: #0070f3;
text-decoration: none;
}
.title a:hover,
.title a:focus,
.title a:active {
text-decoration: underline;
}
.title {
margin: 0;
line-height: 1.15;
font-size: 4rem;
}
.title,
.description {
text-align: center;
}
.description {
margin: 4rem 0;
line-height: 1.5;
font-size: 1.5rem;
}
.code {
background: #fafafa;
border-radius: 5px;
padding: 0.75rem;
font-size: 1.1rem;
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
Bitstream Vera Sans Mono, Courier New, monospace;
}
.grid {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
max-width: 800px;
}
.card {
margin: 1rem;
padding: 1.5rem;
text-align: left;
color: inherit;
text-decoration: none;
border: 1px solid #eaeaea;
border-radius: 10px;
transition: color 0.15s ease, border-color 0.15s ease;
max-width: 300px;
}
.card:hover,
.card:focus,
.card:active {
color: #0070f3;
border-color: #0070f3;
}
.card h2 {
margin: 0 0 1rem 0;
font-size: 1.5rem;
}
.card p {
margin: 0;
font-size: 1.25rem;
line-height: 1.5;
}
.logo {
height: 1em;
margin-left: 0.5rem;
}
@media (max-width: 600px) {
.grid {
width: 100%;
flex-direction: column;
}
}

20
styles/globals.css Executable file
View File

@@ -0,0 +1,20 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
html,
body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}
a {
color: inherit;
text-decoration: none;
}
* {
box-sizing: border-box;
}

11
tailwind.config.js Normal file
View File

@@ -0,0 +1,11 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {},
},
plugins: [],
}

43
tsconfig.json Executable file
View File

@@ -0,0 +1,43 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@app/*": ["./src/app/*"],
"@components/*": ["./src/app/components/*"],
"@js/*": ["src/js"]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}