diff --git a/README.md b/README.md index 615635b..078e0a8 100644 --- a/README.md +++ b/README.md @@ -24,15 +24,19 @@ Built with **Next.js**, **MapLibre GL**, **FastAPI**, and **Python**, it's desig --- -## ⚡ Quick Start (Docker) +## ⚡ Quick Start (Docker or Podman) ```bash git clone https://github.com/BigBodyCobain/Shadowbroker.git cd Shadowbroker -docker-compose up -d +./compose.sh up -d ``` -Open `http://localhost:3000` to view the dashboard! *(Requires Docker)* +Open `http://localhost:3000` to view the dashboard! *(Requires Docker or Podman)* + +`compose.sh` auto-detects `docker compose`, `docker-compose`, `podman compose`, and `podman-compose`. +If both runtimes are installed, you can force Podman with `./compose.sh --engine podman up -d`. +Do not append a trailing `.` to that command; Compose treats it as a service name. --- @@ -161,17 +165,15 @@ Open `http://localhost:3000` to view the dashboard! *(Requires Docker)* ## 🚀 Getting Started -### 🐳 Docker Setup (Recommended for Self-Hosting) +### 🐳 Docker / Podman Setup (Recommended for Self-Hosting) The repo includes a `docker-compose.yml` that builds both images locally. ```bash git clone https://github.com/BigBodyCobain/Shadowbroker.git cd Shadowbroker -# Add your API keys (optional — see Environment Variables below) -cp backend/.env.example backend/.env -# Build and start -docker-compose up -d --build +# Add your API keys in a repo-root .env file (optional — see Environment Variables below) +./compose.sh up -d ``` Open `http://localhost:3000` to view the dashboard. @@ -181,12 +183,15 @@ Open `http://localhost:3000` to view the dashboard. > (e.g. `"9096:8000"`), set `NEXT_PUBLIC_API_URL` before building: > > ```bash -> NEXT_PUBLIC_API_URL=http://192.168.1.50:9096 docker-compose up -d --build +> NEXT_PUBLIC_API_URL=http://192.168.1.50:9096 ./compose.sh up -d --build > ``` > > This is a **build-time** variable (Next.js limitation) — it gets baked into > the frontend during `npm run build`. Changing it requires a rebuild. +If you prefer to call the container engine directly, Podman users can run `podman compose up -d`, or force the wrapper to use Podman with `./compose.sh --engine podman up -d`. +Depending on your local Podman configuration, `podman compose` may still delegate to an external compose provider while talking to the Podman socket. + --- ### 📦 Quick Start (No Code Required) diff --git a/clean_zip.py b/clean_zip.py index d4766bc..89f6f4e 100644 --- a/clean_zip.py +++ b/clean_zip.py @@ -25,6 +25,7 @@ try: add_dir(zipf, 'frontend', {'node_modules', '.next'}) print("Zipping root files...") + zipf.write('compose.sh') zipf.write('docker-compose.yml') zipf.write('start.bat') zipf.write('start.sh') diff --git a/compose.sh b/compose.sh new file mode 100755 index 0000000..1594c99 --- /dev/null +++ b/compose.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +COMPOSE_FILE="$SCRIPT_DIR/docker-compose.yml" +ENGINE="${SHADOWBROKER_CONTAINER_ENGINE:-auto}" +COMPOSE_ARGS=() +COMPOSE_PROVIDER="" + +find_docker_compose() { + if command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1; then + COMPOSE_CMD=(docker compose) + COMPOSE_PROVIDER="docker compose" + return 0 + fi + + if command -v docker-compose >/dev/null 2>&1; then + COMPOSE_CMD=(docker-compose) + COMPOSE_PROVIDER="docker-compose" + return 0 + fi + + return 1 +} + +find_podman_compose() { + if command -v podman >/dev/null 2>&1 && podman compose version >/dev/null 2>&1; then + COMPOSE_CMD=(podman compose) + COMPOSE_PROVIDER="podman compose" + return 0 + fi + + if command -v podman-compose >/dev/null 2>&1; then + COMPOSE_CMD=(podman-compose) + COMPOSE_PROVIDER="podman-compose" + return 0 + fi + + return 1 +} + +if [ ! -f "$COMPOSE_FILE" ]; then + echo "[!] ERROR: Missing compose file: $COMPOSE_FILE" + exit 1 +fi + +while [ "$#" -gt 0 ]; do + case "$1" in + --engine) + if [ "$#" -lt 2 ]; then + echo "[!] ERROR: --engine requires a value: docker, podman, or auto." + exit 1 + fi + ENGINE="$2" + shift 2 + ;; + --engine=*) + ENGINE="${1#*=}" + shift + ;; + *) + COMPOSE_ARGS+=("$1") + shift + ;; + esac +done + +if [ "${#COMPOSE_ARGS[@]}" -eq 0 ]; then + COMPOSE_ARGS=(up -d) +fi + +if [ "${#COMPOSE_ARGS[@]}" -gt 0 ]; then + last_index=$((${#COMPOSE_ARGS[@]} - 1)) + if [ "${COMPOSE_ARGS[$last_index]}" = "." ]; then + echo "[*] Ignoring trailing '.' argument." + unset "COMPOSE_ARGS[$last_index]" + fi +fi + +if [ "${#COMPOSE_ARGS[@]}" -eq 0 ]; then + COMPOSE_ARGS=(up -d) +fi + +COMPOSE_CMD=() + +case "$ENGINE" in + auto) + find_docker_compose || find_podman_compose + ;; + docker) + find_docker_compose + ;; + podman) + find_podman_compose + ;; + *) + echo "[!] ERROR: Unsupported engine '$ENGINE'. Use docker, podman, or auto." + exit 1 + ;; +esac + +if [ "${#COMPOSE_CMD[@]}" -eq 0 ]; then + echo "[!] ERROR: No supported compose command found for engine '$ENGINE'." + echo " Install one of: docker compose, docker-compose, podman compose, or podman-compose." + exit 1 +fi + +if [ "$ENGINE" = "podman" ] && [ "$COMPOSE_PROVIDER" = "podman compose" ]; then + echo "[*] Using (podman): ${COMPOSE_CMD[*]}" + echo "[*] Note: 'podman compose' is Podman's wrapper command and may delegate to docker-compose based on your local Podman configuration." +else + echo "[*] Using ($ENGINE): ${COMPOSE_CMD[*]}" +fi + +"${COMPOSE_CMD[@]}" -f "$COMPOSE_FILE" "${COMPOSE_ARGS[@]}" diff --git a/frontend/.dockerignore b/frontend/.dockerignore index 9a92092..6d69eca 100644 --- a/frontend/.dockerignore +++ b/frontend/.dockerignore @@ -1,11 +1,13 @@ -Dockerfile -.dockerignore -node_modules -npm-debug.log -README.md .next .git .env .env.local .env.* eslint.config.mjs +node_modules +npm-debug.log* +build_logs*.txt +build_output.txt +build_error.txt +errors.txt +server_logs*.txt diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index 5599d0c..c7a9efb 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -70,4 +70,4 @@ body { /* Keep popups fully bright and interactive above the dimmed canvas */ .map-focus-active .maplibregl-popup { z-index: 10 !important; -} \ No newline at end of file +} diff --git a/frontend/tailwind.config.ts b/frontend/tailwind.config.ts new file mode 100644 index 0000000..e30f2d3 --- /dev/null +++ b/frontend/tailwind.config.ts @@ -0,0 +1,7 @@ +import type { Config } from "tailwindcss"; + +const config: Config = { + content: ["./src/**/*.{js,ts,jsx,tsx,mdx}"], +}; + +export default config;