32 lines
1.6 KiB
TypeScript
32 lines
1.6 KiB
TypeScript
/** رنگِ hex را روشن (amount > 0) یا تیره (amount < 0) میکند؛ برای سایهی دکمههای سهبعدی. */
|
|
export function shade(hex: string, amount: number): string {
|
|
const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim());
|
|
if (!m) return hex;
|
|
const n = parseInt(m[1], 16);
|
|
const channel = (c: number) => {
|
|
const v = amount < 0 ? c * (1 + amount) : c + (255 - c) * amount;
|
|
return Math.max(0, Math.min(255, Math.round(v)));
|
|
};
|
|
const r = channel((n >> 16) & 255), g = channel((n >> 8) & 255), b = channel(n & 255);
|
|
return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`;
|
|
}
|
|
|
|
function luminance(hex: string): number {
|
|
const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim());
|
|
if (!m) return 1;
|
|
const n = parseInt(m[1], 16);
|
|
const lin = (c: number) => { const v = c / 255; return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4; };
|
|
return 0.2126 * lin((n >> 16) & 255) + 0.7152 * lin((n >> 8) & 255) + 0.0722 * lin(n & 255);
|
|
}
|
|
|
|
/**
|
|
* همان رنگ، فقط تا جایی تیره میشود که متنِ سفید رویش کنتراستِ دستکم `min` بگیرد
|
|
* (WCAG: ۳ برای متنِ درشت). رنگِ روشن برای آیکن و نوار میماند و فقط پسزمینهی متنِ سفید از این رد میشود،
|
|
* پس هیچ رنگِ تازهای وارد اپ نمیشود، فقط سایهی تیرهترِ همان.
|
|
*/
|
|
export function onWhite(hex: string, min = 3.2): string {
|
|
let c = hex;
|
|
for (let i = 0; i < 12 && 1.05 / (luminance(c) + 0.05) < min; i++) c = shade(c, -0.07);
|
|
return c;
|
|
}
|