Integrate browser geolocation API (#9)

* Add GPS service and nautical base city data

- Implement `GpsService` with methods for position updates and enabling/disabling GPS.
- Introduce test data for nautical base cities with key attributes like population, coordinates, and images.
- Update dependencies in `bun.lock` with required packages such as `geojson`.

* give map a custom style

* shift towards rust exclusivity

* `build.rs` streamlines map build. Added an axum server with the map assets embedded.

* update readmes

* base-map api retrieves geolocation from the navigator of the browser

* make map standalone wry that pulls assets from the server to simulate behavior in bevy

* wip wasm

* wasm build fixed

* fix path ref to assets

---------

Co-authored-by: geoffsee <>
This commit is contained in:
Geoff Seemueller
2025-07-16 17:44:25 -04:00
committed by GitHub
parent 4b3dd2a1c3
commit 602bc5d4b8
49 changed files with 7748 additions and 1279 deletions

120
crates/base-map/build.rs Normal file
View File

@@ -0,0 +1,120 @@
// build.rs
use std::{
env,
fs,
path::{Path, PathBuf},
process::Command,
};
///
/// {
/// "name": "yachtpit",
/// "private": true,
/// "workspaces": ["packages/*"],
/// "scripts": {
/// "build-and-deploy-map": "cd crates/base-map && npm run build && cd ../.. && mkdir -p crates/yachtpit/assets/ui/packages/base-map/dist && cp -r packages/base-map/dist/* crates/yachtpit/assets/ui/packages/base-map/dist/ && cp -r packages/base-map/dist/assets crates/yachtpit/assets/ui/",
/// "postinstall": "npm run build-and-deploy-map"
/// },
/// "devDependencies": {
/// "@types/bun": "latest"
/// },
/// "peerDependencies": {
/// "typescript": "^5"
/// }
/// }
///
fn main() {
// ---------- 0. Locate the map frontend ----------
let map_dir = Path::new("map");
assert!(
map_dir.join("package.json").exists(),
"Expected `map/package.json` is your map frontend in `map/`?"
);
// ---------- 1. Tell Cargo when to rerun ----------
println!("cargo:rerun-if-changed={}", map_dir.join("package.json").display());
println!("cargo:rerun-if-changed={}", map_dir.join("vite.config.ts").display());
println!("cargo:rerun-if-changed={}", map_dir.join("vite.config.js").display());
println!("cargo:rerun-if-changed={}", map_dir.join("src").display());
// ---------- 2. Install & build ----------
run("npm", &["install"], map_dir);
run("npm", &["run", "build"], map_dir); // assumes "build": "tsc -b && vite build" in package.json
// ---------- 3. Copy artefacts following build-and-deploy-map script ----------
let dist = map_dir.join("dist");
let crate_asset_output = out_static_dir();
// Create target directory: crates/yachtpit/assets/ui/packages/base-map/dist
let base_map_dest = Path::new("../yachtpit/assets/ui/packages/base-map/dist");
if base_map_dest.exists() {
fs::remove_dir_all(&base_map_dest).expect("clearing old base-map dist failed");
}
if crate_asset_output.exists() {
fs::remove_dir_all(&crate_asset_output).expect("clearing old base-map dist failed");
}
fs::create_dir_all(&base_map_dest).unwrap();
fs::create_dir_all(&crate_asset_output).unwrap();
// Copy dist/* to crates/yachtpit/assets/ui/packages/base-map/dist/
copy_dir(&dist, &base_map_dest).expect("copying base-map dist/ failed");
copy_dir(&dist, &crate_asset_output).expect("crate asset output failed");
// Copy dist/assets to crates/yachtpit/assets/ui/assets (if assets exist)
let dist_assets = dist.join("assets");
if dist_assets.exists() {
let ui_assets_dest = Path::new("../yachtpit/assets/ui/assets");
if ui_assets_dest.exists() {
fs::remove_dir_all(&ui_assets_dest).expect("clearing old ui assets failed");
}
fs::create_dir_all(&ui_assets_dest).unwrap();
copy_dir(&dist_assets, &ui_assets_dest).expect("copying assets to ui/ failed");
}
}
// -----------------------------------------------------------------------------
// Helpers
// -----------------------------------------------------------------------------
fn run(cmd: &str, args: &[&str], cwd: &Path) {
let ok = Command::new(cmd)
.args(args)
.current_dir(cwd)
.status()
.unwrap_or_else(|_| panic!("failed to spawn `{cmd}`; is it on PATH?"))
.success();
if !ok {
panic!("command `{cmd} {}` failed", args.join(" "));
}
}
/// `$OUT_DIR/../../../static` → a sibling of your crate root inside `target/*/static`.
fn out_static_dir() -> PathBuf {
let out_dir = env::var("OUT_DIR").expect("OUT_DIR env var is set by Cargo");
PathBuf::from(out_dir)
.parent() // build/
.and_then(|p| p.parent()) // <hash>/
.and_then(|p| p.parent()) // release/
.map(|p| p.join("static"))
.expect("could not compute static dir")
}
/// Recursively copy a directory.
fn copy_dir(src: &Path, dst: &Path) -> std::io::Result<()> {
for entry in fs::read_dir(src)? {
let entry = entry?;
let ty = entry.file_type()?;
let dst_path = dst.join(entry.file_name());
if ty.is_dir() {
fs::create_dir_all(&dst_path)?;
copy_dir(&entry.path(), &dst_path)?;
} else {
fs::copy(entry.path(), dst_path)?;
}
}
Ok(())
}