diff --git a/README.md b/README.md index 6f17f42..7959b3c 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,14 @@ PORT=3000 ## Deployment +### Deployment Scripts + +The `scripts/` directory contains all deployment-related files: +- `deploy.sh` - Automated deployment script for Debian 12 (ARM64/x86_64) +- `icewatch.service` - Systemd service file for the application +- `Caddyfile` - Caddy reverse proxy configuration +- `generate-icons.js` - Script to generate PWA icons + ### Quick Deployment (Recommended) See `docs/deployment-quickstart.md` for a simplified deployment guide. @@ -118,6 +126,18 @@ See `docs/deployment-quickstart.md` for a simplified deployment guide. ### Automated Deployment (Debian 12 ARM64/x86_64) 1. **Run the deployment script on your server:** + + **Option A: Use the local deployment script (Recommended)** + ```bash + # Clone the repository first + git clone https://git.deco.sh/deco/ice.git + cd ice + + # Run the local deployment script + sudo bash scripts/deploy.sh + ``` + + **Option B: Download from S3** ```bash # Default: Downloads config from S3 curl -sSL https://ice-puremichigan-lol.s3.amazonaws.com/scripts/deploy.sh | bash @@ -125,6 +145,12 @@ See `docs/deployment-quickstart.md` for a simplified deployment guide. # Alternative: Use local files only (no S3) curl -sSL https://ice-puremichigan-lol.s3.amazonaws.com/scripts/deploy.sh | S3_BUCKET_NAME=none bash ``` + + The deployment script (`scripts/deploy.sh`) automates the entire setup process including: + - Installing required dependencies (Node.js, Git, Caddy) + - Creating system user and directories + - Setting up systemd services + - Configuring Caddy reverse proxy 2. **Deploy your application:** ```bash diff --git a/src/scss/pages/_index.scss b/src/scss/pages/_index.scss index 7e6c3c6..7f1468a 100644 --- a/src/scss/pages/_index.scss +++ b/src/scss/pages/_index.scss @@ -174,7 +174,7 @@ // Specific cell styles td.location-cell { color: var(--text-color); - font-size: $font-size-sm; + font-size: $font-size-md; font-weight: 500; max-width: 250px; overflow: hidden; @@ -184,7 +184,7 @@ td.details-cell { color: var(--text-color); - font-size: 14px; + font-size: $font-size-md; font-weight: 400; max-width: 200px; overflow: hidden; @@ -195,14 +195,15 @@ td.time-cell { color: var(--text-color); - font-size: 12px; + font-size: $font-size-sm; font-weight: 400; } td.remaining-cell { color: var(--text-color); - font-size: 12px; + font-size: $font-size-sm; font-weight: 500; + text-align: center; &.urgent { @include status-indicator(var(--status-danger, $danger-color), white); diff --git a/src/services/MapImageService.ts b/src/services/MapImageService.ts index 622e7df..4a56cb9 100644 --- a/src/services/MapImageService.ts +++ b/src/services/MapImageService.ts @@ -63,8 +63,18 @@ export class MapImageService { // Build Mapbox Static Maps URL with auto-fit let mapboxUrl; if (overlays) { - // Use auto-fit to center on all pins - mapboxUrl = `https://api.mapbox.com/styles/v1/mapbox/streets-v12/static/${overlays}/auto/${options.width}x${options.height}?access_token=${mapboxToken}`; + // Check if we have only one location + const validLocations = locations.filter(loc => loc.latitude && loc.longitude); + + if (validLocations.length === 1) { + // For single location, use fixed zoom level to avoid zooming too close + const location = validLocations[0]; + const zoomLevel = 13; // City-level zoom, shows neighborhood context + mapboxUrl = `https://api.mapbox.com/styles/v1/mapbox/streets-v12/static/${overlays}/${location.longitude},${location.latitude},${zoomLevel}/${options.width}x${options.height}?access_token=${mapboxToken}`; + } else { + // Multiple locations, use auto-fit to show all pins + mapboxUrl = `https://api.mapbox.com/styles/v1/mapbox/streets-v12/static/${overlays}/auto/${options.width}x${options.height}?access_token=${mapboxToken}`; + } } else { // No locations, use Grand Rapids as fallback const fallbackLat = 42.960081464833195; @@ -72,7 +82,10 @@ export class MapImageService { mapboxUrl = `https://api.mapbox.com/styles/v1/mapbox/streets-v12/static/${fallbackLng},${fallbackLat},10/${options.width}x${options.height}?access_token=${mapboxToken}`; } - console.info('Fetching Mapbox static map with auto-fit...'); + console.info('Fetching Mapbox static map...'); + if (overlays && locations.filter(loc => loc.latitude && loc.longitude).length === 1) { + console.info('Using fixed zoom level for single location'); + } console.info('URL:', mapboxUrl.replace(mapboxToken, 'TOKEN_HIDDEN')); return new Promise((resolve) => {