Skip to content

Commit

Permalink
arch: refactor, improved ui color palette
Browse files Browse the repository at this point in the history
  • Loading branch information
arnog committed Dec 8, 2023
1 parent 835e3df commit d31a5a4
Show file tree
Hide file tree
Showing 7 changed files with 428 additions and 312 deletions.
5 changes: 3 additions & 2 deletions src/editor/default-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import { complete, removeSuggestion } from 'editor-mathfield/autocomplete';
import { BACKGROUND_COLORS, FOREGROUND_COLORS } from 'core/color';
import { Atom } from 'core/atom-class';
import { VARIANT_REPERTOIRE } from 'core/modes-math';
import { contrast } from 'ui/colors/utils';
import { _Mathfield } from 'editor-mathfield/mathfield-private';
import { _MenuItemState } from 'ui/menu/menu-item';
import { contrast } from 'ui/colors/contrast';
import { asHexColor } from 'ui/colors/css';

// Return a string from the selection, if all the atoms are character boxes
// (i.e. not fractions, square roots, etc...)
Expand Down Expand Up @@ -197,7 +198,7 @@ function getBackgroundColorSubmenu(mf: _Mathfield): MenuItem[] {
for (const color of Object.keys(BACKGROUND_COLORS)) {
result.push({
class:
(contrast(BACKGROUND_COLORS[color]) === '#000'
(asHexColor(contrast(BACKGROUND_COLORS[color])) === '#000'
? 'dark-contrast'
: 'light-contrast') + ' menu-swatch',

Expand Down
254 changes: 127 additions & 127 deletions src/ui/colors/colors.less
Original file line number Diff line number Diff line change
Expand Up @@ -32,138 +32,138 @@
--neutral-800: #424242;
--neutral-900: #212121;

--red-25: #fff5f5;
--red-50: #ffefee;
--red-100: #ffd6d5;
--red-200: #ffb3b4;
--red-300: #ff8f91;
--red-400: #ff6f71;
--red-500: #ff4f52;
--red-600: #f93f42;
--red-700: #e33539;
--red-800: #c92c30;
--red-900: #a71f23;
--orange-25: #fff7f2;
--orange-50: #fff8f2;
--orange-100: #ffebd9;
--orange-200: #ffdcb8;
--orange-300: #ffc694;
--orange-400: #ffa96d;
--orange-500: #ff8f3f;
--orange-600: #f57e33;
--orange-700: #d86e2a;
--orange-800: #b95e22;
--orange-900: #8f4217;
--brown-25: #fffaf5;
--brown-50: #f7f2e8;
--brown-100: #e7d8c9;
--brown-200: #d1b7a5;
--brown-300: #b78a76;
--brown-400: #9e604c;
--brown-500: #844027;
--brown-600: #733721;
--brown-700: #622c1d;
--brown-800: #4f2218;
--brown-900: #3f1913;
--yellow-25: #fffdf5;
--yellow-50: #fff9e7;
--yellow-100: #fff2c4;
--yellow-200: #ffe59e;
--yellow-300: #ffd875;
--yellow-400: #ffc53d;
--yellow-500: #ffb900;
--yellow-600: #e6a100;
--yellow-700: #bf8f00;
--yellow-800: #997d00;
--yellow-900: #7d6700;
--lime-25: #f9f9e8;
--lime-50: #f5f9e8;
--lime-100: #eaf2c6;
--lime-200: #d9e6a1;
--lime-300: #c5d377;
--lime-400: #b1c24c;
--lime-500: #92b215;
--lime-600: #7ea612;
--lime-700: #6d8f0f;
--lime-800: #5c6d0b;
--lime-900: #3f4a05;
--green-25: #f2f9e8;
--green-50: #e4f7e7;
--green-100: #bceac4;
--green-200: #90dd9d;
--green-300: #64cf75;
--green-400: #42c458;
--green-500: #21ba3a;
--green-600: #1da736;
--green-700: #199533;
--green-800: #137c2e;
--green-900: #0b5726;
--teal-25: #e8f9f9;
--teal-50: #e3f9f9;
--teal-100: #b9f1f1;
--teal-200: #8be7e7;
--teal-300: #5ddddd;
--teal-400: #3ad6d6;
--red-25: #fff8f7;
--red-50: #fff1ef;
--red-100: #ffeae6;
--red-200: #ffcac1;
--red-300: #ffa495;
--red-400: #ff7865;
--red-500: #f21c0d;
--red-600: #e50018;
--red-700: #d30024;
--red-800: #bd002c;
--red-900: #a1002f;
--orange-25: #fffbf8;
--orange-50: #fff7f1;
--orange-100: #fff3ea;
--orange-200: #ffe1c9;
--orange-300: #ffcca2;
--orange-400: #ffb677;
--orange-500: #fe9310;
--orange-600: #f58700;
--orange-700: #ea7c00;
--orange-800: #dc6d00;
--orange-900: #ca5b00;
--brown-25: #fff8ef;
--brown-50: #fff1df;
--brown-100: #ffe9ce;
--brown-200: #ebcca6;
--brown-300: #cdaf8a;
--brown-400: #af936f;
--brown-500: #856a47;
--brown-600: #7f5e34;
--brown-700: #78511f;
--brown-800: #6e4200;
--brown-900: #593200;
--yellow-25: #fffdf9;
--yellow-50: #fffcf2;
--yellow-100: #fffaec;
--yellow-200: #fff2ce;
--yellow-300: #ffe8ab;
--yellow-400: #ffdf85;
--yellow-500: #ffcf33;
--yellow-600: #f1c000;
--yellow-700: #dfb200;
--yellow-800: #c9a000;
--yellow-900: #ad8a00;
--lime-25: #f4ffee;
--lime-50: #e9ffdd;
--lime-100: #ddffca;
--lime-200: #a8fb6f;
--lime-300: #94e659;
--lime-400: #80d142;
--lime-500: #63b215;
--lime-600: #45a000;
--lime-700: #268e00;
--lime-800: #007417;
--lime-900: #005321;
--green-25: #f5fff5;
--green-50: #ebffea;
--green-100: #e0ffdf;
--green-200: #a7ffa7;
--green-300: #5afa65;
--green-400: #45e953;
--green-500: #17cf36;
--green-600: #00b944;
--green-700: #00a34a;
--green-800: #008749;
--green-900: #00653e;
--teal-25: #f3ffff;
--teal-50: #e6fffe;
--teal-100: #d9fffe;
--teal-200: #8dfffe;
--teal-300: #57f4f4;
--teal-400: #43e5e5;
--teal-500: #17cfcf;
--teal-600: #14b7b7;
--teal-700: #129f9f;
--teal-800: #0e7f7f;
--teal-900: #094e4e;
--cyan-25: #e8f9fd;
--cyan-50: #e3f4fd;
--cyan-100: #b8e5f9;
--cyan-200: #89d3f6;
--cyan-300: #5ac1f2;
--cyan-400: #36b4ef;
--teal-600: #00c2c0;
--teal-700: #00b5b1;
--teal-800: #00a49e;
--teal-900: #009087;
--cyan-25: #f7fcff;
--cyan-50: #eff8ff;
--cyan-100: #e7f5ff;
--cyan-200: #c2e6ff;
--cyan-300: #95d5ff;
--cyan-400: #61c4ff;
--cyan-500: #13a7ec;
--cyan-600: #1197d3;
--cyan-700: #1088ba;
--cyan-800: #0e7398;
--cyan-900: #0a5366;
--blue-25: #e8f5fd;
--blue-50: #e2f0fd;
--blue-100: #b6d9fb;
--blue-200: #86c0f9;
--blue-300: #56a6f6;
--blue-400: #3193f4;
--cyan-600: #069eda;
--cyan-700: #0095c9;
--cyan-800: #0088b2;
--cyan-900: #0a7897;
--blue-25: #f7faff;
--blue-50: #eef5ff;
--blue-100: #e5f1ff;
--blue-200: #bfdbff;
--blue-300: #92c2ff;
--blue-400: #63a8ff;
--blue-500: #0d80f2;
--blue-600: #0c75d8;
--blue-700: #0c6abe;
--blue-800: #0b5c9c;
--blue-900: #094668;
--indigo-25: #f0e8fd;
--indigo-50: #ede7f9;
--indigo-100: #d1c2f0;
--indigo-200: #b399e6;
--indigo-300: #9470db;
--indigo-400: #7d52d4;
--indigo-500: #6300ff;
--indigo-600: #5b2fb6;
--indigo-700: #502b9f;
--indigo-800: #422581;
--indigo-900: #2c1d54;
--purple-25: #f9e8fd;
--purple-50: #f4e3fc;
--purple-100: #e3baf8;
--purple-200: #d18cf3;
--purple-300: #be5eee;
--purple-400: #b03cea;
--blue-600: #0077db;
--blue-700: #006dc4;
--blue-800: #0060a7;
--blue-900: #005086;
--indigo-25: #f8f7ff;
--indigo-50: #f1efff;
--indigo-100: #eae7ff;
--indigo-200: #ccc3ff;
--indigo-300: #ac99ff;
--indigo-400: #916aff;
--indigo-500: #63c;
--indigo-600: #5a21b2;
--indigo-700: #4e0b99;
--indigo-800: #3b0071;
--indigo-900: #220040;
--purple-25: #fbf7ff;
--purple-50: #f8f0ff;
--purple-100: #f4e8ff;
--purple-200: #e4c4ff;
--purple-300: #d49aff;
--purple-400: #c36aff;
--purple-500: #a219e6;
--purple-600: #9118cd;
--purple-700: #8116b3;
--purple-800: #6b1492;
--purple-900: #49115f;
--magenta-25: #fde8fd;
--magenta-50: #fde9f3;
--magenta-100: #f9c8e0;
--magenta-200: #f5a3cc;
--magenta-300: #f17eb8;
--magenta-400: #ee63a8;
--purple-600: #9000c4;
--purple-700: #7c009f;
--purple-800: #600073;
--purple-900: #3d0043;
--magenta-25: #fff8fb;
--magenta-50: #fff2f6;
--magenta-100: #ffebf2;
--magenta-200: #ffcddf;
--magenta-300: #ffa8cb;
--magenta-400: #ff7fb7;
--magenta-500: #eb4799;
--magenta-600: #d83f88;
--magenta-700: #c53777;
--magenta-800: #ac2d60;
--magenta-900: #861d3d;
--magenta-600: #da3689;
--magenta-700: #c82179;
--magenta-800: #b00065;
--magenta-900: #8a004c;
}

@media (prefers-color-scheme: dark) {
Expand Down
98 changes: 98 additions & 0 deletions src/ui/colors/contrast.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { Color } from './types';
import { asRgb } from './utils';

/**
* Return a more accurate measure of contrast between a foreground color
* and a background color than WCAG2.0.
*
* Range is approximately -108..108
*
* If result < 0, the foreground is lighter than the background
*
* If abs(result) > 90, suitable for all cases
* If abs(result) < 60, large text
* If abs(result) < 44, spot and non-text
* If abs(result) < 30, minimum contrast for any text
*
* See https://www.myndex.com/APCA/
*/
export function apca(bgColor: Color, fgColor: Color): number {
// APCA calculations are done in sRGB color space
const bgRgb = asRgb(bgColor);
const fgRgb = asRgb(fgColor);

// exponents
const normBG = 0.56;
const normTXT = 0.57;
const revTXT = 0.62;
const revBG = 0.65;

// clamps
const blkThrs = 0.022;
const blkClmp = 1.414;
const loClip = 0.1;
const deltaYmin = 0.0005;

// scalers
// see https://github.com/w3c/silver/issues/645
const scaleBoW = 1.14;
const loBoWoffset = 0.027;
const scaleWoB = 1.14;
const loWoBoffset = 0.027;

function fclamp(Y: number) {
return Y >= blkThrs ? Y : Y + (blkThrs - Y) ** blkClmp;
}

function linearize(val: number) {
const sign = val < 0 ? -1 : 1;
return sign * Math.pow(Math.abs(val), 2.4);
}

// Calculates "screen luminance" with non-standard simple gamma EOTF
// weights should be from CSS Color 4, not the ones here which are via Myndex and copied from Lindbloom
const Yfg = fclamp(
linearize(fgRgb.r / 255) * 0.2126729 +
linearize(fgRgb.g / 255) * 0.7151522 +
linearize(fgRgb.b / 255) * 0.072175
);

const Ybg = fclamp(
linearize(bgRgb.r / 255) * 0.2126729 +
linearize(bgRgb.g / 255) * 0.7151522 +
linearize(bgRgb.b / 255) * 0.072175
);

let S: number, C: number, Sapc: number;

if (Math.abs(Ybg - Yfg) < deltaYmin) C = 0;
else {
if (Ybg > Yfg) {
// dark foreground on light background
S = Ybg ** normBG - Yfg ** normTXT;
C = S * scaleBoW;
} else {
// light foreground on dark background
S = Ybg ** revBG - Yfg ** revTXT;
C = S * scaleWoB;
}
}
if (Math.abs(C) < loClip) Sapc = 0;
else if (C > 0) Sapc = C - loWoBoffset;
else Sapc = C + loBoWoffset;

return Sapc * 100;
}

/** Of two foreground colors, return the one with the highest
* contrast ratio with the background
*/
export function contrast(bgColor: Color, dark?: Color, light?: Color): Color {
light ??= '#fff';
dark ??= '#000';

const lightContrast = apca(bgColor, light);
const darkContrast = apca(bgColor, dark);

return Math.abs(lightContrast) > Math.abs(darkContrast) ? light : dark;
}
Loading

0 comments on commit d31a5a4

Please sign in to comment.