Radial Pattern Background: Beter colors

This commit is contained in:
Alexander Zinchuk 2025-10-14 03:23:21 +02:00
parent 3fd03fbe61
commit 930b36fa78
12 changed files with 29 additions and 37 deletions

View File

@ -38,7 +38,6 @@ const GiftTransferPreview = ({
<RadialPatternBackground
className={styles.backdrop}
backgroundColors={[giftAttributes.backdrop!.centerColor, giftAttributes.backdrop!.edgeColor]}
patternColor={giftAttributes.backdrop?.patternColor}
patternIcon={giftAttributes.pattern?.sticker}
/>
<AnimatedIconFromSticker

View File

@ -132,13 +132,11 @@ const SavedGift = ({
}
const backdropColors = [backdrop.centerColor, backdrop.edgeColor];
const patternColor = backdrop.patternColor;
return (
<RadialPatternBackground
className={styles.radialPattern}
backgroundColors={backdropColors}
patternColor={patternColor}
patternIcon={pattern.sticker}
patternSize={14}
ringsCount={1}

View File

@ -492,7 +492,6 @@ const ProfileInfo = ({
<RadialPatternBackground
backgroundColors={profileColorSet.bgColors}
patternIcon={backgroundEmoji}
patternColor={collectibleEmojiStatus?.patternColor}
patternSize={16}
withLinearGradient={!collectibleEmojiStatus}
className={styles.radialPatternBackground}

View File

@ -6,7 +6,7 @@ import { requestMutation } from '../../../lib/fasterdom/fasterdom';
import { getStickerMediaHash } from '../../../global/helpers';
import buildClassName from '../../../util/buildClassName';
import buildStyle from '../../../util/buildStyle';
import { hex2rgba, rgba2hex } from '../../../util/colors.ts';
import { adjustHsv, getColorLuma, hex2rgb } from '../../../util/colors.ts';
import { preloadImage } from '../../../util/files';
import { REM } from '../helpers/mediaDimensions';
@ -20,8 +20,9 @@ import styles from './RadialPatternBackground.module.scss';
type OwnProps = {
backgroundColors: string[];
patternIcon?: ApiSticker;
patternColor?: string;
patternColor?: number;
patternSize?: number;
centerEmptiness?: number;
ringsCount?: number;
ovalFactor?: number;
withLinearGradient?: boolean;
@ -32,9 +33,10 @@ type OwnProps = {
const BASE_RING_ITEM_COUNT = 8;
const RING_INCREMENT = 0.5;
const CENTER_EMPTINESS = 0.1;
const DEFAULT_CENTER_EMPTINESS = 0.1;
const MAX_RADIUS = 0.42;
const MIN_SIZE = 4 * REM;
const DARK_LUMA_THRESHOLD = 255 * 0.2;
const DEFAULT_PATTERN_SIZE = 20;
const DEFAULT_RINGS_COUNT = 3;
@ -43,8 +45,8 @@ const DEFAULT_OVAL_FACTOR = 1.4;
const RadialPatternBackground = ({
backgroundColors,
patternIcon,
patternColor,
patternSize = DEFAULT_PATTERN_SIZE,
centerEmptiness = DEFAULT_CENTER_EMPTINESS,
ringsCount = DEFAULT_RINGS_COUNT,
ovalFactor = DEFAULT_OVAL_FACTOR,
withLinearGradient,
@ -74,7 +76,7 @@ const RadialPatternBackground = ({
for (let ring = 1; ring <= ringsCount; ring++) {
const ringItemCount = Math.floor(BASE_RING_ITEM_COUNT * (1 + (ring - 1) * RING_INCREMENT));
const ringProgress = ring / ringsCount;
const ringRadius = CENTER_EMPTINESS + (MAX_RADIUS - CENTER_EMPTINESS) * ringProgress;
const ringRadius = centerEmptiness + (MAX_RADIUS - centerEmptiness) * ringProgress;
const angleShift = ring % 2 === 0 ? Math.PI / ringItemCount : 0;
for (let i = 0; i < ringItemCount; i++) {
@ -96,7 +98,7 @@ const RadialPatternBackground = ({
}
}
return coordinates;
}, [clearBottomSector, ovalFactor, ringsCount]);
}, [centerEmptiness, clearBottomSector, ovalFactor, ringsCount]);
useResizeObserver(containerRef, (entry) => {
setContainerSize({
@ -138,13 +140,15 @@ const RadialPatternBackground = ({
ctx.drawImage(emojiImage, renderX - size / 2, renderY - size / 2, size, size);
});
ctx.fillStyle = adjustBrightness(backgroundColors[1] ?? backgroundColors[0], -0.075);
const patternColor = backgroundColors[1] ?? backgroundColors[0];
const isDark = getColorLuma(hex2rgb(patternColor)) < DARK_LUMA_THRESHOLD;
ctx.fillStyle = adjustHsv(patternColor, 0.5, isDark ? 0.28 : -0.28);
ctx.globalCompositeOperation = 'source-in';
ctx.fillRect(0, 0, width, height);
const radialGradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, width / 2);
radialGradient.addColorStop(0.75, 'rgb(255 255 255 / 0)');
radialGradient.addColorStop(1, 'rgb(255 255 255 / 0.75)');
radialGradient.addColorStop(0, 'rgb(255 255 255 / 0.4)');
radialGradient.addColorStop(1, 'rgb(255 255 255 / 0.9)');
// Scale around the gradient center
ctx.translate(centerX, centerY);
@ -161,7 +165,7 @@ const RadialPatternBackground = ({
useEffect(() => {
draw();
}, [emojiImage, patternColor, patternPositions, yPosition, ovalFactor]);
}, [emojiImage, patternPositions, yPosition, ovalFactor]);
useLayoutEffect(() => {
const { width, height } = getContainerSize();
@ -198,15 +202,3 @@ const RadialPatternBackground = ({
};
export default memo(RadialPatternBackground);
function adjustBrightness(hex: string, delta: number) {
const factor = 1 + delta;
const [r, g, b, a] = hex2rgba(hex);
return rgba2hex([
Math.min(255, Math.round(r * factor)),
Math.min(255, Math.round(g * factor)),
Math.min(255, Math.round(b * factor)),
a ?? 255,
]);
}

View File

@ -49,8 +49,10 @@ const WebPageUniqueGift = ({
<RadialPatternBackground
className={styles.background}
backgroundColors={backgroundColors}
patternColor={backdrop!.patternColor}
patternIcon={pattern!.sticker}
centerEmptiness={0.15}
ringsCount={2}
ovalFactor={1.2}
/>
</div>
<div ref={stickerRef} className={styles.stickerWrapper}>

View File

@ -97,7 +97,6 @@ const StarGiftAction = ({
<RadialPatternBackground
className={styles.uniqueBackground}
backgroundColors={backgroundColors}
patternColor={backdrop.patternColor}
patternIcon={pattern.sticker}
patternSize={14}
yPosition={9.5 * REM}

View File

@ -126,13 +126,11 @@ function GiftItemStar({
}
const backdropColors = [backdrop.centerColor, backdrop.edgeColor];
const patternColor = backdrop.patternColor;
return (
<RadialPatternBackground
className={styles.radialPattern}
backgroundColors={backdropColors}
patternColor={patternColor}
patternIcon={pattern.sticker}
/>
);

View File

@ -512,7 +512,6 @@ const GiftResaleFilters: FC<StateProps & OwnProps> = ({
<RadialPatternBackground
className={styles.backdrop}
backgroundColors={[backdrop.centerColor, backdrop.edgeColor]}
patternColor={backdrop.patternColor}
/>
<div className={styles.backdropAttributeMenuItemText}>
{backdrop.name}

View File

@ -66,13 +66,11 @@ const UniqueGiftHeader = ({
const radialPatternBackdrop = useMemo(() => {
const backdropColors = [backdropAttribute.centerColor, backdropAttribute.edgeColor];
const patternColor = backdropAttribute.patternColor;
return (
<RadialPatternBackground
className={styles.radialPattern}
backgroundColors={backdropColors}
patternColor={patternColor}
patternIcon={patternAttribute.sticker}
/>
);

View File

@ -67,13 +67,11 @@ const GiftStatusInfoModal = ({
if (!emojiStatus || !isOpen) return undefined;
const backdropColors = [emojiStatus.centerColor, emojiStatus.edgeColor];
const patternColor = emojiStatus.patternColor;
return (
<RadialPatternBackground
className={styles.radialPattern}
backgroundColors={backdropColors}
patternColor={patternColor}
patternIcon={patternIcon.customEmoji}
/>
);

View File

@ -98,7 +98,6 @@ const GiftWithdrawModal = ({ modal, hasPassword, passwordHint }: OwnProps & Stat
<RadialPatternBackground
className={styles.backdrop}
backgroundColors={[giftAttributes.backdrop!.centerColor, giftAttributes.backdrop!.edgeColor]}
patternColor={giftAttributes.backdrop?.patternColor}
patternIcon={giftAttributes.pattern?.sticker}
/>
<AnimatedIconFromSticker

View File

@ -1,5 +1,5 @@
import { preloadImage } from './files';
import { lerp } from './math.ts';
import { clamp, lerp } from './math.ts';
const LUMA_THRESHOLD = 128;
@ -272,3 +272,14 @@ export function lerpRgbaObj(start: Rgba, end: Rgba, interpolationRatio: number):
return { r, g, b, a };
}
export function adjustHsv(hex: string, satDelta: number, valDelta: number) {
const hsva = rgba2hsva(hex2rgba(hex));
const [h, , , a] = hsva;
let [, s, v] = hsva;
if (s > 0.1 && s < 0.9) s = clamp(s + satDelta, 0, 1);
v = clamp(v + valDelta, 0, 1);
return rgba2hex(hsva2rgba([h, s, v, a]));
}