diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 9da6dbf..37e251f 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -5,6 +5,14 @@ on: branches: ["main"] paths: - "website/**" + - "shared/**" + - "webApp/**" + - "gradle/**" + - "gradlew" + - "gradlew.bat" + - "build.gradle.kts" + - "settings.gradle.kts" + - "gradle.properties" - ".github/workflows/pages.yml" workflow_dispatch: @@ -26,12 +34,26 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Set up JDK + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: "21" + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + - name: Build web app + run: ./gradlew :webApp:wasmJsBrowserDistribution + - name: Assemble site + run: | + mkdir -p _site/app + cp -r website/. _site/ + cp -r webApp/build/dist/wasmJs/productionExecutable/. _site/app/ - name: Setup Pages uses: actions/configure-pages@v5 - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: - path: "./website" + path: "./_site" - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 725f2ae..18d6753 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ xcodebuild*.log .gradle/ .idea/ +/website/app/ .*.swp .*.swo .DS_Store diff --git a/AGENTS.md b/AGENTS.md index ca06560..1384ea2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,11 +8,14 @@ real trial-and-error to get right. ## What this is SatsPrice is a Kotlin Multiplatform app, currently released on iOS, macOS, -and Android (see README's Supported Platforms/Download and Install). Web and -Desktop/JVM are real future release targets too — `desktopApp` already has -full native packaging configured (DMG/MSI/DEB, see its `build.gradle.kts`) — -but neither has a release/CI pipeline set up yet, so treat them as -not-yet-shipped rather than dev-only. The app converts between BTC, Sats, +and Android (see README's Supported Platforms/Download and Install). +Desktop/JVM is a real future release target — `desktopApp` already has full +native packaging configured (DMG/MSI/DEB, see its `build.gradle.kts`) — but +has no release/CI pipeline set up yet, so treat it as not-yet-shipped rather +than dev-only. Web is a step ahead of Desktop: `.github/workflows/pages.yml` +builds `:webApp:wasmJsBrowserDistribution` and publishes it alongside the +marketing site to `satsprice.app/app/` on every push to `main` — see +"Website and web app deployment" below. The app converts between BTC, Sats, and fiat currencies using live exchange rates (Coinbase, CoinGecko, or a manually typed-in rate). @@ -149,6 +152,27 @@ fallback instead (`data/db/LocalStorageStores.kt`), which does survive page reloads, just scoped to the browser profile/origin (cleared by clearing site data, not shared across browsers/devices). +## Website and web app deployment + +`website/` is a static marketing site (plain HTML/CSS/JS, no build step of +its own) deployed to `satsprice.app` via GitHub Pages +(`.github/workflows/pages.yml`). That workflow does more than upload +`website/` as-is: it also runs `./gradlew :webApp:wasmJsBrowserDistribution` +and copies the result into `website/app/` before publishing, so the live +Compose web app is reachable at `satsprice.app/app/` and linked from the +site (nav, hero, download section) via `/app/`. + +- `website/app/` is git-ignored — it's build output, generated fresh by CI + (and locally by the script below), never committed. +- To reproduce the production layout locally (site + web app together, + `/app/` links working): `./website/serve-local.sh [port]`. It builds the + wasmJs distribution, copies it into `website/app/`, and serves + `website/` with `python3 -m http.server`. +- If you change the Pages workflow, remember `paths:` in the trigger + includes `webApp/**`/`shared/**`/Gradle files, not just `website/**` — + a shared-code change that affects the web app should also redeploy the + site. + ## Testing and verification - `shared/src/commonTest` holds the real unit test suite (pure Kotlin, diff --git a/README.md b/README.md index 859fbc1..0e437b4 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ height="70">](https://github.com/tyiu/sats-price/releases) ## Supported Platforms -iOS 16.0+ • macOS 13.0+ • Android 7.0+ +iOS 16.0+ • macOS 13.0+ • Android 7.0+ • [Web](https://satsprice.app/app/) (any modern browser) ## Screenshots @@ -75,6 +75,9 @@ options: - Wasm target (faster, modern browsers): `./gradlew :webApp:wasmJsBrowserDevelopmentRun` - JS target (slower, supports older browsers): `./gradlew :webApp:jsBrowserDevelopmentRun` - iOS app: open the [/iosApp](./iosApp) directory in Xcode and run it from there. +- [Website](./website) (with the web app built and served at `/app/`, matching production): + `./website/serve-local.sh` (serves at http://localhost:8000 by default; pass a port number to + override) ### Running tests diff --git a/website/index.html b/website/index.html index 196c22d..4f583cc 100644 --- a/website/index.html +++ b/website/index.html @@ -4,7 +4,7 @@ SatsPrice — Bitcoin Price & Sats Converter - + @@ -22,6 +22,7 @@ Features Screenshots Download + Web App Code @@ -37,6 +38,7 @@ Features Screenshots Download + Web App GitHub @@ -60,6 +62,11 @@ See screenshots +

+ Don't want to install anything? + Try it in your browser → +

+
@@ -73,6 +80,10 @@ Android + + + Web +
@@ -162,7 +173,7 @@
💻

Native on every platform

-

SwiftUI on iOS and macOS, Compose Multiplatform on Android — built with Kotlin Multiplatform to feel right at home on each device, not like a port.

+

SwiftUI on iOS and macOS, Compose Multiplatform on Android and Web — built with Kotlin Multiplatform to feel right at home on each device, not like a port.

@@ -279,10 +290,17 @@
+
or
+ +
+ Open the web app — no install required +
+
🍎 iOS 16.0+ 🖥️ macOS 13.0+ 🤖 Android 7.0+ + 🌐 Web — any modern browser

diff --git a/website/serve-local.sh b/website/serve-local.sh new file mode 100755 index 0000000..e05f4fd --- /dev/null +++ b/website/serve-local.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# Builds the web app, drops it into website/app/, and serves the whole +# website locally so the /app/ links behave like they do in production. +set -euo pipefail + +PORT="${1:-8000}" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(dirname "$SCRIPT_DIR")" + +echo "Building web app (wasmJs)..." +"$REPO_ROOT/gradlew" -p "$REPO_ROOT" :webApp:wasmJsBrowserDistribution + +echo "Copying web app into website/app/..." +mkdir -p "$SCRIPT_DIR/app" +cp -r "$REPO_ROOT/webApp/build/dist/wasmJs/productionExecutable/." "$SCRIPT_DIR/app/" + +echo "Serving website at http://localhost:$PORT/ (web app at http://localhost:$PORT/app/)" +cd "$SCRIPT_DIR" && python3 -m http.server "$PORT" diff --git a/website/styles.css b/website/styles.css index de458c0..da8d59c 100644 --- a/website/styles.css +++ b/website/styles.css @@ -268,6 +268,20 @@ h1, h2, h3, h4 { margin-top: 32px; } +.hero-webapp { + margin-top: 18px; + font-size: 14px; + color: var(--text-faint); +} + +.hero-webapp a { + color: var(--gold); + font-weight: 600; + text-decoration: none; +} + +.hero-webapp a:hover { text-decoration: underline; } + .platform-pills { display: flex; flex-wrap: wrap; @@ -652,6 +666,26 @@ h1, h2, h3, h4 { .badge-link.obtainium img, .badge-link.github img { height: 56px; } +.webapp-divider { + display: flex; + align-items: center; + justify-content: center; + gap: 14px; + margin-top: 30px; + color: var(--text-faint); + font-size: 13px; +} + +.webapp-divider::before, +.webapp-divider::after { + content: ""; + height: 1px; + width: 80px; + background: var(--border); +} + +.webapp-cta { margin-top: 18px; } + .version-row { margin-top: 38px; display: flex;