feat: HG mode - změna obrázků, animace v modálech
CI / Generate TypeScript types (push) Successful in 10s
CI / Server unit tests (push) Successful in 27s
CI / Build server (push) Successful in 29s
CI / Build client (push) Successful in 43s
CI / Playwright E2E tests (push) Successful in 2m2s
CI / Build and push Docker image (push) Successful in 45s
CI / Notify (push) Successful in 2s

This commit is contained in:
Ondřej Anděl committed 2026-10-12 14:34:55 +02:00
1 parent 5147651e7c
commit 2a54a1d41f
7 files changed
+198 -2

No files matched your search

+48
View File
@@ -0,0 +1,48 @@
/** Obrázky stylu Hell Girl (plamen + symbol ohně) — server je cachuje, viz server/src/confetti.ts. */
const HELLGIRL_IMAGES_URL = '/api/confetti/hellgirl';
export type HellGirlImages = { flame: string, symbol: string };
let imagesPromise: Promise<HellGirlImages | undefined> | undefined;
/** Načte URL obrázků (jednou za běh aplikace). Při chybě vrátí undefined a příště to zkusí znovu. */
export const loadHellGirlImages = (): Promise<HellGirlImages | undefined> => {
imagesPromise ??= fetch(HELLGIRL_IMAGES_URL)
.then(r => r.ok ? r.json() : undefined)
.then(images => images?.flame && images?.symbol ? images as HellGirlImages : undefined)
.catch(() => undefined)
.then(images => {
if (!images) imagesPromise = undefined;
return images;
});
return imagesPromise;
};
/**
* Z obrázku symbolu (rudý tvar na bílém pozadí) udělá masku — průhlednost podle toho, jak
* moc pixel není bílý (zelený kanál). Barvu pak symbolu dodá CSS gradientem v paletě stylu.
*/
export const createSymbolMask = (src: string, size = 96): Promise<string | undefined> => new Promise(resolve => {
const img = new Image();
img.onload = () => {
try {
const canvas = document.createElement('canvas');
canvas.width = canvas.height = size;
const ctx = canvas.getContext('2d');
if (!ctx) return resolve(undefined);
ctx.drawImage(img, 0, 0, size, size);
const pixels = ctx.getImageData(0, 0, size, size);
const data = pixels.data;
for (let i = 0; i < data.length; i += 4) {
data[i + 3] = 255 - data[i + 1];
data[i] = data[i + 1] = data[i + 2] = 0;
}
ctx.putImageData(pixels, 0, 0);
resolve(canvas.toDataURL('image/png'));
} catch {
resolve(undefined);
}
};
img.onerror = () => resolve(undefined);
img.src = src;
});