diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..f5a0364 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,45 @@ +name: Release + +# PR / manual dispatch -> package on all 3 OSes WITHOUT publishing (QA dry-run). +# Pushing a v* tag -> build + publish artifacts to the matching GitHub Release. +on: + pull_request: + paths: + - 'package.json' + - 'package-lock.json' + - 'src/**' + - 'scripts/**' + - 'build/**' + - '.github/workflows/release.yml' + workflow_dispatch: + push: + tags: ['v*'] + +permissions: + contents: write + +jobs: + package: + name: package (${{ matrix.os }}) + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + env: + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' + CSC_IDENTITY_AUTO_DISCOVERY: 'false' # no code-signing cert in CI (unsigned builds) + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + - run: npm ci + - run: npm run build + - name: electron-builder (publish on tags only) + run: npx --no-install electron-builder --publish ${{ startsWith(github.ref, 'refs/tags/') && 'always' || 'never' }} + - name: List built artifacts + shell: bash + run: ls -la release || true diff --git a/build/icon.ico b/build/icon.ico index b94e85a..7ed7c41 100644 Binary files a/build/icon.ico and b/build/icon.ico differ diff --git a/build/icon.png b/build/icon.png index ca379b9..77bc90f 100644 Binary files a/build/icon.png and b/build/icon.png differ diff --git a/package.json b/package.json index bc326a4..ccd9cde 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "devdeck", - "version": "0.1.0", + "version": "0.2.0", "description": "Project command deck — at-a-glance state + claude -c resume", "main": "dist/main/main.js", "type": "commonjs", @@ -23,7 +23,6 @@ "build": { "appId": "com.soursea.devdeck", "productName": "DevDeck", - "icon": "build/icon.ico", "files": [ "dist/**/*", "package.json" @@ -32,13 +31,27 @@ "output": "release" }, "win": { - "target": [{ "target": "nsis", "arch": ["x64"] }] + "target": [{ "target": "nsis", "arch": ["x64"] }], + "icon": "build/icon.ico" }, "nsis": { "oneClick": false, "perMachine": false, "allowToChangeInstallationDirectory": true, "artifactName": "${productName}-${version}-Setup.${ext}" + }, + "mac": { + "target": [{ "target": "dmg", "arch": ["arm64", "x64"] }], + "category": "public.app-category.developer-tools", + "icon": "build/icon.png", + "artifactName": "${productName}-${version}-${arch}.${ext}" + }, + "linux": { + "target": ["AppImage", "deb"], + "category": "Development", + "icon": "build/icon.png", + "maintainer": "writingdeveloper ", + "artifactName": "${productName}-${version}-${arch}.${ext}" } }, "devDependencies": { diff --git a/scripts/gen-icons.js b/scripts/gen-icons.js index ed8d0d3..cf043cf 100644 --- a/scripts/gen-icons.js +++ b/scripts/gen-icons.js @@ -10,7 +10,7 @@ const ROOT = path.join(__dirname, '..'); const MARK = fs.readFileSync(path.join(ROOT, 'design', 'logos', 'mark.svg'), 'utf8'); function svgAt512({ withDot = true, flat = false } = {}) { - let s = MARK.replace('width="256" height="256"', 'width="512" height="512"'); + let s = MARK.replace('width="256" height="256"', 'width="1024" height="1024"'); if (!withDot) s = s.replace(/]*\/>/, ''); // tiny sizes stay crisp // The soft drop shadow looks great large but muddies into a faint horizontal // band under the card at tray sizes (≤32px) — strip it so small icons stay crisp. @@ -34,7 +34,7 @@ async function capture512(win, opts, tag) { app.disableHardwareAcceleration(); app.whenReady().then(async () => { const win = new BrowserWindow({ - width: 512, height: 512, show: false, frame: false, transparent: true, + width: 1024, height: 1024, show: false, frame: false, transparent: true, webPreferences: { offscreen: true }, }); const full = await capture512(win, { withDot: true, flat: false }, 'full'); // 48px+: shadow reads fine @@ -48,11 +48,11 @@ app.whenReady().then(async () => { return src.resize({ width: size, height: size, quality: 'best' }).toPNG(); }; const png = {}; - for (const s of [...icoSizes, 512]) { png[s] = pngAt(s); console.log('made', s, png[s].length, 'bytes'); } + for (const s of [...icoSizes, 512, 1024]) { png[s] = pngAt(s); console.log('made', s, png[s].length, 'bytes'); } fs.mkdirSync(path.join(ROOT, 'build'), { recursive: true }); fs.mkdirSync(path.join(ROOT, 'src', 'assets'), { recursive: true }); - fs.writeFileSync(path.join(ROOT, 'build', 'icon.png'), png[512]); + fs.writeFileSync(path.join(ROOT, 'build', 'icon.png'), png[1024]); fs.writeFileSync(path.join(ROOT, 'build', 'icon.ico'), packIco(icoSizes.map((s) => png[s]), icoSizes)); fs.writeFileSync(path.join(ROOT, 'src', 'assets', 'icon-256.png'), png[256]); fs.writeFileSync(path.join(ROOT, 'src', 'assets', 'tray.png'), png[32]); diff --git a/src/assets/icon-256.png b/src/assets/icon-256.png index 770dd7a..a9018b6 100644 Binary files a/src/assets/icon-256.png and b/src/assets/icon-256.png differ diff --git a/src/assets/tray.png b/src/assets/tray.png index 8a4b28b..1c24524 100644 Binary files a/src/assets/tray.png and b/src/assets/tray.png differ