ci / mobile / mobile (Metro-бандл Android) (push) Successful in 2m30s
ci / ts / ts (packages + web) (push) Successful in 3m29s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 2m10s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 56s
ci / desktop / rust (desktop proxy) (push) Successful in 3m15s
52 lines
2.8 KiB
JavaScript
52 lines
2.8 KiB
JavaScript
import { copyFileSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
import { createRequire } from 'node:module';
|
|
import { dirname, join, resolve } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { spawnSync } from 'node:child_process';
|
|
|
|
// All platform assets derive from the editable web SVG. Requires workspace dependencies.
|
|
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
const desktop = join(root, 'apps/desktop');
|
|
const require = createRequire(join(desktop, 'package.json'));
|
|
const cli = require.resolve('@tauri-apps/cli/tauri.js');
|
|
const scratch = join(root, 'artifacts/icon-build');
|
|
const source = join(root, 'apps/web/public/favicon.svg');
|
|
const svg = readFileSync(source, 'utf8');
|
|
const body = svg.replace(/<svg[^>]*>/, '').replace('</svg>', '');
|
|
mkdirSync(scratch, { recursive: true });
|
|
|
|
function render(input, output, sizes = []) {
|
|
mkdirSync(output, { recursive: true });
|
|
const result = spawnSync(process.execPath, [cli, 'icon', input, '--output', output,
|
|
...sizes.flatMap(size => ['--png', String(size)])], { cwd: desktop, stdio: 'inherit' });
|
|
if (result.error) throw result.error;
|
|
if (result.status !== 0) throw new Error(`Icon generation failed: ${input}`);
|
|
}
|
|
|
|
function variant(name, contents, size, destination) {
|
|
const input = join(scratch, `${name}.svg`);
|
|
const output = join(scratch, name);
|
|
writeFileSync(input, `<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">${contents}</svg>\n`);
|
|
render(input, output, [size]);
|
|
mkdirSync(dirname(destination), { recursive: true });
|
|
copyFileSync(join(output, `${size}x${size}.png`), destination);
|
|
}
|
|
|
|
const native = join(scratch, 'desktop');
|
|
render(source, native);
|
|
for (const name of ['32x32.png', '64x64.png', '128x128.png', '128x128@2x.png', 'icon.png', 'icon.ico', 'icon.icns']) {
|
|
copyFileSync(join(native, name), join(desktop, 'src-tauri/icons', name));
|
|
}
|
|
copyFileSync(join(native, '32x32.png'), join(root, 'apps/web/public/favicon-32.png'));
|
|
const background = '<rect width="512" height="512" fill="#05070D"/>';
|
|
variant('touch', background + body, 180, join(root, 'apps/web/public/apple-touch-icon.png'));
|
|
variant('mobile', background + body, 1024, join(root, 'apps/mobile/assets/icon.png'));
|
|
// The complete orb fits inside Android's central 66/108 safe-zone circle.
|
|
variant('adaptive', `<g transform="translate(92.16 92.16) scale(.64)">${body}</g>`, 1024,
|
|
join(root, 'apps/mobile/assets/adaptive-icon.png'));
|
|
const mono = body.replace(/<defs>[\s\S]*?<\/defs>/, '').replace(/<circle[^>]*\/>/, '')
|
|
.replaceAll('url(#note)', '#FFFFFF');
|
|
variant('monochrome', `<g transform="translate(51.2 51.2) scale(.8)">${mono}</g>`, 1024,
|
|
join(root, 'apps/mobile/assets/monochrome-icon.png'));
|
|
console.log('Updated desktop, Android, and browser icons.');
|