diff --git a/README.md b/README.md index 3563808..57203d5 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ for the same Firefox publishing flow. For an explicit version check, pass the current tag after `--`: ```bash -VERSTAK_BROWSER_ENV=/path/to/.env npm run publish:github -- v2.0.5 +VERSTAK_BROWSER_ENV=/path/to/.env npm run publish:github -- v2.0.6 ``` Release output: diff --git a/chromium/manifest.json b/chromium/manifest.json index a2188af..82687c8 100644 --- a/chromium/manifest.json +++ b/chromium/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Verstak Bridge", - "version": "2.0.5", + "version": "2.0.6", "description": "Send pages, selections, links, and files to the local Verstak browser inbox.", "author": "Verstak", "homepage_url": "https://github.com/mirivlad/verstak-browser-extension", diff --git a/firefox/manifest.json b/firefox/manifest.json index d53e31f..cad128a 100644 --- a/firefox/manifest.json +++ b/firefox/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Verstak Bridge", - "version": "2.0.5", + "version": "2.0.6", "description": "Send pages, selections, links, and files to the local Verstak browser inbox.", "author": "Verstak", "homepage_url": "https://github.com/mirivlad/verstak-browser-extension", diff --git a/package-lock.json b/package-lock.json index c337c38..53fba3f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "verstak-browser-extension", - "version": "2.0.5", + "version": "2.0.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "verstak-browser-extension", - "version": "2.0.5", + "version": "2.0.6", "devDependencies": { "web-ext": "^8.3.0" } diff --git a/package.json b/package.json index b6f6660..8fe72d4 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "verstak-browser-extension", - "version": "2.0.5", + "version": "2.0.6", "private": true, "description": "Verstak browser capture extension for Chromium and Firefox", "license": "AGPL-3.0-or-later", "scripts": { "build": "node scripts/build-extension.js", - "test": "node scripts/test-manifests.js && node scripts/test-hostname.js && node scripts/test-activity-tracker.js && node scripts/test-protocol.js && node scripts/test-i18n.js && node scripts/test-popup-settings.js && node scripts/test-popup-select-style.js && node scripts/test-popup-catalog-fallback.js && node scripts/test-background-i18n.js && node scripts/test-firefox-github-release.js", + "test": "node scripts/test-manifests.js && node scripts/test-icons.js && node scripts/test-hostname.js && node scripts/test-activity-tracker.js && node scripts/test-protocol.js && node scripts/test-i18n.js && node scripts/test-popup-settings.js && node scripts/test-popup-select-style.js && node scripts/test-popup-catalog-fallback.js && node scripts/test-background-i18n.js && node scripts/test-firefox-github-release.js", "sign:firefox": "./scripts/sign-firefox-xpi.sh", "release:firefox": "./scripts/release-firefox-xpi.sh", "publish:firefox": "./scripts/publish-firefox-github-release.sh", diff --git a/release-notes/v2.0.6.md b/release-notes/v2.0.6.md new file mode 100644 index 0000000..89c28a4 --- /dev/null +++ b/release-notes/v2.0.6.md @@ -0,0 +1,13 @@ +## Highlights + +- Replaced the legacy orange extension symbol with the current Verstak workbench + icon in every browser size: 16, 48, and 128 pixels. +- Chromium and Firefox packages now use the same icon source as the Verstak + desktop application. + +## Главное + +- Старый оранжевый знак расширения заменён на актуальный фирменный значок + Верстака во всех размерах: 16, 48 и 128 пикселей. +- Пакеты Chromium и Firefox теперь используют тот же исходный знак, что и + приложение Верстак. diff --git a/scripts/generate-icons.sh b/scripts/generate-icons.sh new file mode 100755 index 0000000..558c59a --- /dev/null +++ b/scripts/generate-icons.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +MAGICK="${MAGICK_BIN:-magick}" +SOURCE="$ROOT/shared/icons/verstak.svg" + +if ! command -v "$MAGICK" >/dev/null; then + echo "ImageMagick is required to generate browser extension icons: $MAGICK not found" >&2 + exit 1 +fi + +for size in 16 48 128; do + "$MAGICK" -background none "$SOURCE" -resize "${size}x${size}" \ + "PNG32:$ROOT/shared/icons/icon${size}.png" +done + +echo "generated browser extension icons from $SOURCE" diff --git a/scripts/test-firefox-github-release.js b/scripts/test-firefox-github-release.js index e1dea25..f787f9b 100644 --- a/scripts/test-firefox-github-release.js +++ b/scripts/test-firefox-github-release.js @@ -6,23 +6,23 @@ const packageManifest = require('../package.json'); const chromiumManifest = require('../chromium/manifest.json'); const firefoxManifest = require('../firefox/manifest.json'); -const version = '2.0.5'; -const asset = 'verstak-firefox-2.0.5.xpi'; +const version = '2.0.6'; +const asset = 'verstak-firefox-2.0.6.xpi'; assert.equal(packageManifest.version, version); assert.equal(chromiumManifest.version, version); assert.equal(firefoxManifest.version, version); -assert.equal(release.releaseTag(version), 'v2.0.5'); +assert.equal(release.releaseTag(version), 'v2.0.6'); assert.equal( release.releaseAssetURL(version, asset), - 'https://github.com/mirivlad/verstak-browser-extension/releases/download/v2.0.5/verstak-firefox-2.0.5.xpi', + 'https://github.com/mirivlad/verstak-browser-extension/releases/download/v2.0.6/verstak-firefox-2.0.6.xpi', ); assert.deepEqual(release.updateManifest('verstak-bridge@verstak.app', version, asset), { addons: { 'verstak-bridge@verstak.app': { updates: [{ - version: '2.0.5', - update_link: 'https://github.com/mirivlad/verstak-browser-extension/releases/download/v2.0.5/verstak-firefox-2.0.5.xpi', + version: '2.0.6', + update_link: 'https://github.com/mirivlad/verstak-browser-extension/releases/download/v2.0.6/verstak-firefox-2.0.6.xpi', }], }, }, diff --git a/scripts/test-icons.js b/scripts/test-icons.js new file mode 100644 index 0000000..a618b86 --- /dev/null +++ b/scripts/test-icons.js @@ -0,0 +1,102 @@ +#!/usr/bin/env node +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const zlib = require('zlib'); + +const root = path.resolve(__dirname, '..'); +const source = fs.readFileSync(path.join(root, 'shared', 'icons', 'verstak.svg'), 'utf8'); + +assert.match(source, /fill="#1c2f4a"/i, 'icon source must define the Verstak navy'); +assert.match(source, /fill="#72d2b3"/i, 'icon source must define the Verstak mint'); + +function paeth(left, up, upperLeft) { + const estimate = left + up - upperLeft; + const leftDistance = Math.abs(estimate - left); + const upDistance = Math.abs(estimate - up); + const upperLeftDistance = Math.abs(estimate - upperLeft); + if (leftDistance <= upDistance && leftDistance <= upperLeftDistance) return left; + if (upDistance <= upperLeftDistance) return up; + return upperLeft; +} + +function pngColors(file) { + const png = fs.readFileSync(file); + assert.deepStrictEqual(png.subarray(0, 8), Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]), `${file} must be PNG`); + + let offset = 8; + let width; + let height; + let bitDepth; + let colorType; + let palette; + const idat = []; + while (offset < png.length) { + const length = png.readUInt32BE(offset); + const type = png.toString('ascii', offset + 4, offset + 8); + const data = png.subarray(offset + 8, offset + 8 + length); + offset += length + 12; + if (type === 'IHDR') { + width = data.readUInt32BE(0); + height = data.readUInt32BE(4); + bitDepth = data[8]; + colorType = data[9]; + } else if (type === 'PLTE') { + palette = data; + } else if (type === 'IDAT') { + idat.push(data); + } + } + + assert.equal(bitDepth, 8, `${file} must use 8-bit samples`); + assert.ok([2, 3, 6].includes(colorType), `${file} must use RGB, palette, or RGBA pixels`); + const bytesPerPixel = colorType === 6 ? 4 : colorType === 2 ? 3 : 1; + const rowSize = width * bytesPerPixel; + const decoded = zlib.inflateSync(Buffer.concat(idat)); + const colors = new Set(); + let readOffset = 0; + let previous = Buffer.alloc(rowSize); + + for (let y = 0; y < height; y += 1) { + const filter = decoded[readOffset++]; + const encoded = decoded.subarray(readOffset, readOffset + rowSize); + readOffset += rowSize; + const row = Buffer.alloc(rowSize); + for (let x = 0; x < rowSize; x += 1) { + const left = x >= bytesPerPixel ? row[x - bytesPerPixel] : 0; + const up = previous[x]; + const upperLeft = x >= bytesPerPixel ? previous[x - bytesPerPixel] : 0; + if (filter === 0) row[x] = encoded[x]; + else if (filter === 1) row[x] = (encoded[x] + left) & 255; + else if (filter === 2) row[x] = (encoded[x] + up) & 255; + else if (filter === 3) row[x] = (encoded[x] + Math.floor((left + up) / 2)) & 255; + else if (filter === 4) row[x] = (encoded[x] + paeth(left, up, upperLeft)) & 255; + else assert.fail(`${file} has unsupported PNG filter ${filter}`); + } + for (let x = 0; x < width; x += 1) { + if (colorType === 3) { + const paletteOffset = row[x] * 3; + colors.add(palette.subarray(paletteOffset, paletteOffset + 3).toString('hex')); + } else { + const pixelOffset = x * bytesPerPixel; + colors.add(row.subarray(pixelOffset, pixelOffset + 3).toString('hex')); + } + } + previous = row; + } + return { width, height, colors }; +} + +for (const [name, size, needsMint] of [ + ['icon16.png', 16, false], + ['icon48.png', 48, true], + ['icon128.png', 128, true], +]) { + const icon = pngColors(path.join(root, 'shared', 'icons', name)); + assert.equal(icon.width, size, `${name} width`); + assert.equal(icon.height, size, `${name} height`); + assert.ok(icon.colors.has('1c2f4a'), `${name} must contain the Verstak navy`); + if (needsMint) assert.ok(icon.colors.has('72d2b3'), `${name} must contain the Verstak mint`); +} + +console.log('browser extension icon tests passed'); diff --git a/shared/icons/icon128.png b/shared/icons/icon128.png index 89d1388..6c07363 100644 Binary files a/shared/icons/icon128.png and b/shared/icons/icon128.png differ diff --git a/shared/icons/icon16.png b/shared/icons/icon16.png index f6ea1c0..c60eeee 100644 Binary files a/shared/icons/icon16.png and b/shared/icons/icon16.png differ diff --git a/shared/icons/icon48.png b/shared/icons/icon48.png index 101ba7e..1bd2842 100644 Binary files a/shared/icons/icon48.png and b/shared/icons/icon48.png differ diff --git a/shared/icons/verstak.svg b/shared/icons/verstak.svg new file mode 100644 index 0000000..23a9fe8 --- /dev/null +++ b/shared/icons/verstak.svg @@ -0,0 +1,5 @@ + + + + +