fix desktop tray icon telegram topics and checkin intervals

This commit is contained in:
cita
2026-03-20 12:16:00 +08:00
parent 2de5eebf29
commit 220f786204
23 changed files with 808 additions and 42 deletions
+48 -7
View File
@@ -6,6 +6,7 @@ import sharp from 'sharp';
export const DESKTOP_ICON_SIZE = 512;
export const DESKTOP_ICON_PADDING = 40;
export const DESKTOP_ICON_RADIUS = 96;
export const DESKTOP_TRAY_TEMPLATE_PADDING = 152;
function createRoundedMask(size, cornerRadius) {
return Buffer.from(
@@ -44,34 +45,73 @@ async function renderDesktopIconBuffer({
.toBuffer();
}
async function renderTrayTemplateIconBuffer({
sourcePath,
size = DESKTOP_ICON_SIZE,
padding = DESKTOP_TRAY_TEMPLATE_PADDING,
}) {
const innerSize = Math.max(1, size - padding * 2);
const alphaMask = await sharp(sourcePath)
.resize(innerSize, innerSize, {
fit: 'contain',
background: { r: 0, g: 0, b: 0, alpha: 0 },
})
.ensureAlpha()
.extractChannel('alpha')
.png()
.toBuffer();
return sharp({
create: {
width: size,
height: size,
channels: 4,
background: { r: 0, g: 0, b: 0, alpha: 1 },
},
})
.composite([{ input: alphaMask, left: padding, top: padding, blend: 'dest-in' }])
.png()
.toBuffer();
}
export async function generateDesktopIconAssets({
sourcePath = join(process.cwd(), 'src', 'web', 'public', 'logo.png'),
buildOutputPath = join(process.cwd(), 'build', 'desktop-icon.png'),
webOutputPath = join(process.cwd(), 'src', 'web', 'public', 'desktop-icon.png'),
trayTemplateOutputPath = join(process.cwd(), 'src', 'web', 'public', 'desktop-tray-template.png'),
size = DESKTOP_ICON_SIZE,
padding = DESKTOP_ICON_PADDING,
cornerRadius = DESKTOP_ICON_RADIUS,
} = {}) {
const outputBuffer = await renderDesktopIconBuffer({
sourcePath,
size,
padding,
cornerRadius,
});
const [outputBuffer, trayTemplateBuffer] = await Promise.all([
renderDesktopIconBuffer({
sourcePath,
size,
padding,
cornerRadius,
}),
renderTrayTemplateIconBuffer({
sourcePath,
size,
}),
]);
await Promise.all([
mkdir(dirname(buildOutputPath), { recursive: true }),
mkdir(dirname(webOutputPath), { recursive: true }),
mkdir(dirname(trayTemplateOutputPath), { recursive: true }),
]);
await Promise.all([
sharp(outputBuffer).toFile(buildOutputPath),
sharp(outputBuffer).toFile(webOutputPath),
sharp(trayTemplateBuffer).toFile(trayTemplateOutputPath),
]);
return {
buildOutputPath,
webOutputPath,
trayTemplateOutputPath,
};
}
@@ -81,5 +121,6 @@ if (isDirectRun) {
const outputs = await generateDesktopIconAssets();
console.log(`[metapi-desktop] Generated desktop icons:
- ${outputs.buildOutputPath}
- ${outputs.webOutputPath}`);
- ${outputs.webOutputPath}
- ${outputs.trayTemplateOutputPath}`);
}
+19 -1
View File
@@ -21,13 +21,14 @@ afterEach(async () => {
});
describe('generateDesktopIconAssets', () => {
it('writes rounded desktop icon outputs for build and runtime usage', async () => {
it('writes rounded desktop icon outputs and a tray template asset', async () => {
const { generateDesktopIconAssets } = await import('./generate-icons.mjs');
const dir = await makeTempDir();
const sourcePath = join(dir, 'logo.png');
const buildOutputPath = join(dir, 'build.png');
const webOutputPath = join(dir, 'desktop-icon.png');
const trayTemplateOutputPath = join(dir, 'desktop-tray-template.png');
await sharp({
create: {
@@ -42,15 +43,19 @@ describe('generateDesktopIconAssets', () => {
sourcePath,
buildOutputPath,
webOutputPath,
trayTemplateOutputPath,
});
const buildMeta = await sharp(buildOutputPath).metadata();
const webMeta = await sharp(webOutputPath).metadata();
const trayMeta = await sharp(trayTemplateOutputPath).metadata();
expect(buildMeta.width).toBe(512);
expect(buildMeta.height).toBe(512);
expect(webMeta.width).toBe(512);
expect(webMeta.height).toBe(512);
expect(trayMeta.width).toBe(512);
expect(trayMeta.height).toBe(512);
const { data, info } = await sharp(buildOutputPath)
.ensureAlpha()
@@ -64,5 +69,18 @@ describe('generateDesktopIconAssets', () => {
expect(await sharp(buildOutputPath).png().toBuffer())
.toEqual(await sharp(webOutputPath).png().toBuffer());
const trayBuffer = await sharp(trayTemplateOutputPath)
.ensureAlpha()
.raw()
.toBuffer({ resolveWithObject: true });
expect(alphaAt(trayBuffer.data, trayBuffer.info.width, 0, 0)).toBe(0);
expect(alphaAt(trayBuffer.data, trayBuffer.info.width, Math.floor(trayBuffer.info.width / 2), Math.floor(trayBuffer.info.height / 2))).toBe(255);
const trayCenterOffset = (Math.floor(trayBuffer.info.height / 2) * trayBuffer.info.width + Math.floor(trayBuffer.info.width / 2)) * 4;
expect(trayBuffer.data[trayCenterOffset]).toBe(0);
expect(trayBuffer.data[trayCenterOffset + 1]).toBe(0);
expect(trayBuffer.data[trayCenterOffset + 2]).toBe(0);
});
});