diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index fc7658ef8..078e8523b 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -11,14 +11,27 @@ jobs: matrix: include: - os: macos-latest + target: --mac dmg artifact: macos-dmg pattern: release/*.dmg - os: ubuntu-latest + target: --linux AppImage artifact: linux-appimage pattern: release/*.AppImage + - os: ubuntu-latest + target: --linux flatpak + artifact: linux-flatpak + pattern: release/*.flatpak + container: ghcr.io/flathub-infra/flatpak-github-actions:freedesktop-25.08 + container-options: --privileged runs-on: ${{ matrix.os }} + # Ignored if empty + container: + image: ${{ matrix.container || '' }} + options: ${{ matrix.container-options || '' }} + steps: - name: Checkout code uses: actions/checkout@v4 @@ -39,11 +52,33 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile + # electron-builder always auto-installs the Electron base app via + # "flatpak install --user". flatpak-github-actions' container only has + # flathub as a system remote. Work this around by pre-installing + # (then the bundler just updates it). + - name: Install Flatpak deps + if: matrix.artifact == 'linux-flatpak' + run: flatpak install --system --noninteractive flathub org.electronjs.Electron2.BaseApp//25.08 + + # flatpak-builder's rofiles-fuse doesn't work in containers (no fuse), + # and electron-builder has no way to pass arguments to flatpak-builder, + # so make a wrapper. + - name: Make a flatpak-builder wrapper + if: matrix.artifact == 'linux-flatpak' + run: | + fb="$(command -v flatpak-builder)" + mv "$fb" "$fb.real" + printf '#!/bin/sh\nexec "%s" --disable-rofiles-fuse "$@"\n' "$fb.real" >"$fb" + chmod +x "$fb" + - name: Build - run: pnpm run electron:dist + run: pnpm run electron:dist ${{ matrix.target }} env: # don't try to codesign / notarize in CI CSC_IDENTITY_AUTO_DISCOVERY: false + # flatpak-bundler pipes flatpak's stdout/stderr through 'debug', + # hiding all the diagnostics. + DEBUG: "@malept/flatpak-bundler" - name: Upload artifact uses: actions/upload-artifact@v4 diff --git a/assets/desktop-icon/build.mjs b/assets/desktop-icon/build.mjs index 834eec815..46db5edf0 100644 --- a/assets/desktop-icon/build.mjs +++ b/assets/desktop-icon/build.mjs @@ -1,10 +1,14 @@ -// Generate the electron-builder desktop icons from the glyph SVG, all in this -// dir: icon.png (full-bleed square, for Linux/Windows) and icon.icns (macOS -// squircle with Apple's standard padding, since macOS doesn't auto-round). -// Re-run after changing the glyph: `node assets/desktop-icon/build.mjs`. -// Requires ImageMagick (`magick`) and, for the .icns, macOS `iconutil`. +/* Generate the electron-builder desktop icons from the glyph SVG, all in this + * dir. None of Windows/Linux/macOS auto-round, so generate the icons here: + * + * 1. icon.png - full-bleed square for Windows, + * 2. icon-linux.{svg,png} - Linux squircle (GNOME HIG padding and rounding), + * 3. icon.icns - macOS squircle with Apple's standard padding. + * + * Re-run after changing the glyph: `node assets/desktop-icon/build.mjs`. + * Requires ImageMagick (`magick`) and, for the .icns, macOS `iconutil`. */ import {spawnSync} from 'child_process'; -import {mkdirSync, readFileSync, rmSync} from 'fs'; +import {mkdirSync, readFileSync, rmSync, writeFileSync} from 'fs'; import {dirname, join} from 'path'; import {fileURLToPath} from 'url'; @@ -18,6 +22,12 @@ const BG_TO = '#D59EFF'; const MAC_CONTENT = 824; const MAC_MARGIN = (SIZE - MAC_CONTENT) / 2; const MAC_RADIUS = 185; +// GNOME app-icon: a 103×103 rounded square (8px corners) centered in the +// 128 grid. Our icon is 1024x1024, so scaled dimensions are: 824px content, +// 100px margin, 64px radius (same content box as macOS, softer corners). +const GNOME_CONTENT = 824; +const GNOME_MARGIN = (SIZE - GNOME_CONTENT) / 2; +const GNOME_RADIUS = 64; const glyph = readFileSync(join(dir, 'icon.svg'), 'utf8'); const viewBox = glyph.match(/viewBox\s*=\s*"\s*0\s+0\s+([\d.]+)\s+([\d.]+)\s*"/); @@ -57,10 +67,15 @@ function render(svg, out) { } const square = buildSvg({size: SIZE, offset: 0, radius: 0}); -const pngPath = join(dir, 'icon.png'); -render(square, pngPath); +render(square, join(dir, 'icon.png')); console.log('wrote assets/desktop-icon/icon.png'); +const linux = buildSvg({size: GNOME_CONTENT, offset: GNOME_MARGIN, radius: GNOME_RADIUS}); +writeFileSync(join(dir, 'icon-linux.svg'), linux); +console.log('wrote assets/desktop-icon/icon-linux.svg'); +render(linux, join(dir, 'icon-linux.png')); +console.log('wrote assets/desktop-icon/icon-linux.png'); + if (process.platform !== 'darwin') { console.log('[build-app-icon] skipping .icns (needs macOS iconutil)'); process.exit(0); diff --git a/assets/desktop-icon/icon-linux.png b/assets/desktop-icon/icon-linux.png new file mode 100644 index 000000000..1ec4987b2 Binary files /dev/null and b/assets/desktop-icon/icon-linux.png differ diff --git a/assets/desktop-icon/icon-linux.svg b/assets/desktop-icon/icon-linux.svg new file mode 100644 index 000000000..528704bfa --- /dev/null +++ b/assets/desktop-icon/icon-linux.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/electron-builder.yml b/electron-builder.yml index dbc1e1d78..40e62bb28 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -1,4 +1,6 @@ -appId: desu.inutweb +# Flatpak requires appId to be a valid D-Bus bus name. A valid D-Bus bus name +# contains at least 3 segments (intended for reverse dns notation). +appId: pet.tei.inutweb productName: inutweb copyright: abolish copyright law @@ -33,9 +35,23 @@ win: linux: category: Network - icon: assets/desktop-icon/icon.png + icon: assets/desktop-icon/icon-linux.png + syncDesktopName: true target: - AppImage + - flatpak + +# electron-builder defaults to 20.08 for some reason; it's not even +# on Flathub anymore. +flatpak: + runtimeVersion: "25.08" + baseVersion: "25.08" + # electron-builder doesn't add the png icon specified above because it's + # 1024px, and flatpak target skips anything >512px. + # Add a proper scalable icon manually. + files: + - - assets/desktop-icon/icon-linux.svg + - /share/icons/hicolor/scalable/apps/pet.tei.inutweb.svg nsis: oneClick: false diff --git a/package.json b/package.json index 6154708d0..3a17ad1e8 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "license": "GPL-3.0-only", "main": "dist-electron/main.js", + "desktopName": "pet.tei.inutweb.desktop", "engines": { "node": ">=22" }, @@ -72,4 +73,4 @@ "vitest": "^4.1.0" }, "packageManager": "pnpm@10.34.3+sha512.f2c531b08829d7be7f03c90addc266615f9c5477463e4bf1d275cb263ce9ea57cf0d5599110d94649a9bb3fed9f0b5efcea74a7016b61532a24cb9ad87860c1d" -} \ No newline at end of file +}