sforkowany z mirror/soapbox
Porównaj commity
5 Commity
develop
...
color-impr
Autor | SHA1 | Data |
---|---|---|
Alex Gleason | 6f9de037ed | |
Alex Gleason | 0f43ae091c | |
Alex Gleason | 9758958c35 | |
Alex Gleason | b3ad112b30 | |
Alex Gleason | 0fd8209df6 |
|
@ -1,3 +1,4 @@
|
|||
import { convert } from 'chromatism';
|
||||
import {
|
||||
Map as ImmutableMap,
|
||||
List as ImmutableList,
|
||||
|
@ -6,7 +7,7 @@ import {
|
|||
} from 'immutable';
|
||||
import trimStart from 'lodash/trimStart';
|
||||
|
||||
import { toTailwind } from 'soapbox/utils/tailwind';
|
||||
import { generatePalette, HSLDelta, HSLPaletteDelta, hslShift } from 'soapbox/utils/hsl';
|
||||
import { generateAccent } from 'soapbox/utils/theme';
|
||||
|
||||
import { normalizeAd } from './ad';
|
||||
|
@ -18,33 +19,73 @@ import type {
|
|||
CryptoAddress,
|
||||
} from 'soapbox/types/soapbox';
|
||||
|
||||
const DEFAULT_COLORS = ImmutableMap<string, any>({
|
||||
success: ImmutableMap({
|
||||
50: '#f0fdf4',
|
||||
100: '#dcfce7',
|
||||
200: '#bbf7d0',
|
||||
300: '#86efac',
|
||||
400: '#4ade80',
|
||||
500: '#22c55e',
|
||||
600: '#16a34a',
|
||||
700: '#15803d',
|
||||
800: '#166534',
|
||||
900: '#14532d',
|
||||
}),
|
||||
danger: ImmutableMap({
|
||||
50: '#fef2f2',
|
||||
100: '#fee2e2',
|
||||
200: '#fecaca',
|
||||
300: '#fca5a5',
|
||||
400: '#f87171',
|
||||
500: '#ef4444',
|
||||
600: '#dc2626',
|
||||
700: '#b91c1c',
|
||||
800: '#991b1b',
|
||||
900: '#7f1d1d',
|
||||
}),
|
||||
'sea-blue': '#2feecc',
|
||||
});
|
||||
const SEED_COLOR_DELTAS: Record<string, HSLDelta> = {
|
||||
gray: [ 5.640168899709693, -71.25227844367963, 42.13578614093887 ],
|
||||
primary: [ 0, 0, 0 ],
|
||||
secondary: [ -264.41907148380454, 3.47034415017923, 16.72498531826924 ],
|
||||
success: [ -132.16963284744344, 22.729414313887375, 27.93609003256976 ],
|
||||
danger: [ -254.94219506629216, -0.22042936848366423, 12.675221477923778 ],
|
||||
};
|
||||
|
||||
const PALETTE_DELTAS: Record<string, HSLPaletteDelta> = {
|
||||
gray: {
|
||||
'50': [ 0.22937683270356501, -1.5864743831017971, 15.567851989991112 ],
|
||||
'100': [ 34.311838173845615, -1.2141376862436761, 13.938662622153828 ],
|
||||
'200': [ -6.726925619450583, -1.3474032449266322, 12.477917572764795 ],
|
||||
'300': [ -6.803051539716591, -1.1039007790831639, 9.366828937389187 ],
|
||||
'400': [ 7.251025534431051, -0.7564434934117528, 6.308652406934627 ],
|
||||
'500': [ 0, 0, 0 ],
|
||||
'600': [ 0.528273854081192, 5.024155622767128, -28.942510078414657 ],
|
||||
'700': [ 0.753585022750201, 9.244324145778112, -42.27720854061048 ],
|
||||
'800': [ -3.38885080806142, 38.377108591613, -72.05591766747844 ],
|
||||
'900': [ -3.6531980550540197, 49.0899586185372, -77.8873736703074 ],
|
||||
},
|
||||
primary: {
|
||||
'50': [ -12.328127784192901, -67.24292824683431, 53.24283923089697 ],
|
||||
'100': [ -11.411261541571491, -62.439158441446395, 49.48672631248416 ],
|
||||
'200': [ -9.416727076537427, -53.876459261840154, 42.38848417160097 ],
|
||||
'300': [ -3.767637832203661, -27.858121091970574, 19.530562906640746 ],
|
||||
'400': [ -1.6746167286863738, -15.676431605871016, 7.808121295055564 ],
|
||||
'500': [ 0, 0, 0 ],
|
||||
'600': [ -0.003909458369605545, 2.5576939049011287, -7.724998167194286 ],
|
||||
'700': [ 0.11738125411591227, -5.255248276711185, -21.911667783093854 ],
|
||||
'800': [ 0.1328770612169592, -9.311121602273253, -29.182323283856825 ],
|
||||
'900': [ 1.9869708446556729, -22.162319825142433, -35.75158752936853 ],
|
||||
},
|
||||
// @ts-ignore
|
||||
secondary: {
|
||||
'100': [ 347.880182793043, -68.47214895215055, 32.867057572173536 ],
|
||||
'200': [ 350.05034589809117, -52.65112125949534, 21.087557709426832 ],
|
||||
'300': [ 354.031215223099, -23.94959581070235, 7.6397685025461755 ],
|
||||
'400': [ -1.739008662838304, -13.175216574546795, 3.6494520365984613 ],
|
||||
'500': [ 0, 0, 0 ],
|
||||
'600': [ 0.27516723567895696, -0.06197773826696107, -0.02163844988602648 ],
|
||||
},
|
||||
success: {
|
||||
'50': [ 6.272318640784931, -87.82006472610146, 27.923961374235645 ],
|
||||
'100': [ 7.515812986311346, -76.24726912121697, 26.015113902196305 ],
|
||||
'200': [ 6.682412508442582, -58.98301894933322, 22.183456696291486 ],
|
||||
'300': [ 5.042191328515884, -32.36248565174746, 16.65634548562005 ],
|
||||
'400': [ 2.176996549793728, -9.407758928036145, 8.956568283122635 ],
|
||||
'500': [ 0, 0, 0 ],
|
||||
'600': [ -0.372610730302938, 1.0253878418950535, -11.388518702503106 ],
|
||||
'700': [ 0.5145707207430519, -0.9085081381356162, -23.343759036504466 ],
|
||||
'800': [ 1.8284285283559427, -4.840289897227791, -32.88658597113674 ],
|
||||
'900': [ 3.143760008542955, -7.518152045294627, -39.533036861110965 ],
|
||||
},
|
||||
danger: {
|
||||
'50': [ -0.12913498368561527, -70.44886946123935, 41.43265384536481 ],
|
||||
'100': [ -0.0488135435926349, -67.15618734554207, 37.13987057891991 ],
|
||||
'200': [ -0.02122364058786097, -61.17995574356704, 30.822488851023962 ],
|
||||
'300': [ -0.008445121602528971, -49.40898982365067, 21.29509643080908 ],
|
||||
'400': [ -0.0021433776363899426, -25.474902071013723, 9.156088139819957 ],
|
||||
'500': [ 0, 0, 0 ],
|
||||
'600': [ 0.0006646718484049075, 14.619377779600981, -7.0385269603369665 ],
|
||||
'700': [ 0.0007147927161721412, 15.964147857357688, -15.008669041883302 ],
|
||||
'800': [ 0.0005467342060985203, 11.610574809571574, -21.760068390290982 ],
|
||||
'900': [ 0.00015621259826481548, 2.9773216728644343, -26.91230815141926 ],
|
||||
},
|
||||
};
|
||||
|
||||
export const PromoPanelItemRecord = ImmutableRecord({
|
||||
icon: '',
|
||||
|
@ -147,8 +188,23 @@ const normalizeAccentColor = (soapboxConfig: SoapboxConfigMap): SoapboxConfigMap
|
|||
};
|
||||
|
||||
const normalizeColors = (soapboxConfig: SoapboxConfigMap): SoapboxConfigMap => {
|
||||
const colors = DEFAULT_COLORS.mergeDeep(soapboxConfig.get('colors'));
|
||||
return toTailwind(soapboxConfig.set('colors', colors));
|
||||
const hsluv = convert(soapboxConfig.get('brandColor') || '#0482d8').hsluv;
|
||||
const brandColor = { h: hsluv.hu, s: hsluv.s, l: hsluv.l };
|
||||
|
||||
const colors = Object.keys(SEED_COLOR_DELTAS).reduce((acc, curr) => {
|
||||
const seed = hslShift(brandColor, SEED_COLOR_DELTAS[curr]);
|
||||
const hslPalette = generatePalette(seed, PALETTE_DELTAS[curr]);
|
||||
const hexColors = Object.keys(hslPalette).reduce((acc, curr) => {
|
||||
const hsl = (hslPalette as any)[curr as any];
|
||||
const hex = convert({ hu: hsl.h, s: hsl.s, l: hsl.l }).hex;
|
||||
acc[curr] = hex;
|
||||
return acc;
|
||||
}, {} as any);
|
||||
acc[curr] = hexColors;
|
||||
return acc;
|
||||
}, {} as any);
|
||||
|
||||
return soapboxConfig.set('colors', fromJS(colors));
|
||||
};
|
||||
|
||||
const maybeAddMissingColors = (soapboxConfig: SoapboxConfigMap): SoapboxConfigMap => {
|
||||
|
@ -156,7 +212,7 @@ const maybeAddMissingColors = (soapboxConfig: SoapboxConfigMap): SoapboxConfigMa
|
|||
|
||||
const missing = ImmutableMap({
|
||||
'gradient-start': colors.getIn(['primary', '500']),
|
||||
'gradient-end': colors.getIn(['accent', '500']),
|
||||
'gradient-end': colors.getIn(['primary', '500']),
|
||||
'accent-blue': colors.getIn(['primary', '600']),
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
import {
|
||||
hslShift,
|
||||
expandPalette,
|
||||
paletteToDelta,
|
||||
HSLPaletteDelta,
|
||||
} from '../hsl';
|
||||
|
||||
test('hslShift()', () => {
|
||||
expect(hslShift({ h: 50, s: 50, l: 50 }, [-200, 10, 0]))
|
||||
.toEqual({ h: 210, s: 60, l: 50 });
|
||||
|
||||
expect(hslShift({ h: 1, s: 2, l: 3 }, [0, 0, 0]))
|
||||
.toEqual({ h: 1, s: 2, l: 3 });
|
||||
|
||||
expect(hslShift({ h: 0, s: 100, l: 0 }, [-1, 1, -1]))
|
||||
.toEqual({ h: 359, s: 100, l: 0 });
|
||||
|
||||
expect(hslShift({ h: 50, s: 50, l: 50 }, [-360, 10, 0]))
|
||||
.toEqual({ h: 50, s: 60, l: 50 });
|
||||
|
||||
expect(hslShift({ h: 50, s: 50, l: 50 }, [200, 10, 0]))
|
||||
.toEqual({ h: 250, s: 60, l: 50 });
|
||||
});
|
||||
|
||||
test('expandPalette()', () => {
|
||||
const palette = {
|
||||
200: { h: 7, s: 7, l: 7 },
|
||||
500: { h: 50, s: 50, l: 50 },
|
||||
};
|
||||
|
||||
const paletteDelta: HSLPaletteDelta = {
|
||||
50: [-10, -100, 7],
|
||||
100: [0, 0, 0],
|
||||
200: [0, 0, 0],
|
||||
300: [0, 0, 0],
|
||||
400: [0, 0, 0],
|
||||
500: [0, 0, 0],
|
||||
600: [0, 0, 0],
|
||||
700: [0, 0, 0],
|
||||
800: [0, 0, 0],
|
||||
900: [10, 100, -7],
|
||||
};
|
||||
|
||||
const expected = {
|
||||
50: { h: 40, s: 0, l: 57 },
|
||||
100: { h: 50, s: 50, l: 50 },
|
||||
200: { h: 7, s: 7, l: 7 },
|
||||
300: { h: 50, s: 50, l: 50 },
|
||||
400: { h: 50, s: 50, l: 50 },
|
||||
500: { h: 50, s: 50, l: 50 },
|
||||
600: { h: 50, s: 50, l: 50 },
|
||||
700: { h: 50, s: 50, l: 50 },
|
||||
800: { h: 50, s: 50, l: 50 },
|
||||
900: { h: 60, s: 100, l: 43 },
|
||||
};
|
||||
|
||||
expect(expandPalette(palette, paletteDelta)).toEqual(expected);
|
||||
});
|
||||
|
||||
test('paletteToDelta()', () => {
|
||||
const palette = {
|
||||
50: { h: 40, s: 0, l: 57 },
|
||||
100: { h: 50, s: 50, l: 50 },
|
||||
200: { h: 7, s: 7, l: 7 },
|
||||
300: { h: 50, s: 50, l: 50 },
|
||||
400: { h: 50, s: 50, l: 50 },
|
||||
500: { h: 50, s: 50, l: 50 },
|
||||
600: { h: 50, s: 50, l: 50 },
|
||||
700: { h: 50, s: 50, l: 50 },
|
||||
800: { h: 50, s: 50, l: 50 },
|
||||
900: { h: 60, s: 100, l: 43 },
|
||||
};
|
||||
|
||||
const expected = {
|
||||
50: [-10, -50, 7],
|
||||
100: [0, 0, 0],
|
||||
200: [-43, -43, -43],
|
||||
300: [0, 0, 0],
|
||||
400: [0, 0, 0],
|
||||
500: [0, 0, 0],
|
||||
600: [0, 0, 0],
|
||||
700: [0, 0, 0],
|
||||
800: [0, 0, 0],
|
||||
900: [10, 50, -7],
|
||||
};
|
||||
|
||||
expect(paletteToDelta(palette)).toEqual(expected);
|
||||
});
|
|
@ -0,0 +1,84 @@
|
|||
import type { Hsl } from 'soapbox/types/colors';
|
||||
|
||||
/** A neutral color. */
|
||||
const GRAY: Hsl = { h: 0, s: 50, l: 50 };
|
||||
|
||||
/** Modulo (`%`) in both directions. */
|
||||
// https://stackoverflow.com/a/39740009
|
||||
const wrapAround = (value: number, delta: number, max: number): number => {
|
||||
return (max + (value + delta)) % max;
|
||||
};
|
||||
|
||||
/** Clamp the value within the range of `min` and `max`. */
|
||||
// https://stackoverflow.com/a/47837835
|
||||
const minmax = (
|
||||
value: number,
|
||||
min: number,
|
||||
max: number,
|
||||
) => Math.min(max, Math.max(min, value));
|
||||
|
||||
/**
|
||||
* Represents an HSL color shift.
|
||||
*
|
||||
* For example, `[-20, 10, 0]` means "-20deg hue, +10% saturation, unchanged lightness".
|
||||
*/
|
||||
type HSLDelta = [hDelta: number, sDelta: number, lDelta: number];
|
||||
|
||||
/** Tailwind color shade. */
|
||||
type Shade = '50' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900';
|
||||
/** Tailwind color palette with HSL. */
|
||||
type HSLPalette = Record<Shade, Hsl>;
|
||||
/** Tailwind color palette delta map (in HSL). */
|
||||
type HSLPaletteDelta = Record<Shade, HSLDelta>;
|
||||
|
||||
/** Alter the color by the given delta. */
|
||||
const hslShift = (seed: Hsl, delta: HSLDelta): Hsl => {
|
||||
return {
|
||||
h: wrapAround(seed.h, delta[0], 360),
|
||||
s: minmax(seed.s + delta[1], 0, 100),
|
||||
l: minmax(seed.l + delta[2], 0, 100),
|
||||
};
|
||||
};
|
||||
|
||||
/** Generate a color palette from a single color. */
|
||||
const generatePalette = (seed: Hsl, paletteDelta: HSLPaletteDelta): HSLPalette => {
|
||||
const shades = Object.keys(paletteDelta) as Shade[];
|
||||
|
||||
return shades.reduce((result: HSLPalette, shade: Shade) => {
|
||||
const delta = paletteDelta[shade];
|
||||
result[shade] = hslShift(seed, delta);
|
||||
return result;
|
||||
}, {} as HSLPalette);
|
||||
};
|
||||
|
||||
/** Expands a partial color palette, filling in the gaps. */
|
||||
const expandPalette = (palette: Partial<HSLPalette>, paletteDelta: HSLPaletteDelta): HSLPalette => {
|
||||
const seed = palette['500'] || GRAY;
|
||||
const generated = generatePalette(seed, paletteDelta);
|
||||
return Object.assign(generated, palette);
|
||||
};
|
||||
|
||||
/** Convert a complete color palette into a delta map. */
|
||||
const paletteToDelta = (palette: HSLPalette): HSLPaletteDelta => {
|
||||
const seed = palette['500'];
|
||||
const shades = Object.keys(palette) as Shade[];
|
||||
|
||||
return shades.reduce((result: HSLPaletteDelta, shade: Shade) => {
|
||||
const color = palette[shade];
|
||||
result[shade] = [
|
||||
color.h - seed.h,
|
||||
minmax(color.s - seed.s, -100, 100),
|
||||
minmax(color.l - seed.l, -100, 100),
|
||||
];
|
||||
return result;
|
||||
}, {} as HSLPaletteDelta);
|
||||
};
|
||||
|
||||
export {
|
||||
hslShift,
|
||||
generatePalette,
|
||||
expandPalette,
|
||||
paletteToDelta,
|
||||
HSLDelta,
|
||||
HSLPaletteDelta,
|
||||
};
|
|
@ -1,3 +1,4 @@
|
|||
import { convert } from 'chromatism';
|
||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
|
||||
import tintify from 'soapbox/utils/colors';
|
||||
|
@ -54,3 +55,11 @@ export const toTailwind = (soapboxConfig: SoapboxConfig): SoapboxConfig => {
|
|||
|
||||
return soapboxConfig.set('colors', legacyColors.mergeDeep(colors));
|
||||
};
|
||||
|
||||
export const convertPalette = (palette: TailwindColorPalette, type: string) => {
|
||||
return Object.keys(palette).reduce((acc, curr) => {
|
||||
// @ts-ignore
|
||||
acc[curr] = convert(palette[curr])[type];
|
||||
return acc;
|
||||
}, {} as any);
|
||||
};
|
|
@ -105,6 +105,7 @@
|
|||
"bowser": "^2.11.0",
|
||||
"browserslist": "^4.16.6",
|
||||
"cheerio": "^1.0.0-rc.10",
|
||||
"chromatism": "^3.0.0",
|
||||
"clsx": "^1.2.1",
|
||||
"copy-webpack-plugin": "^9.0.1",
|
||||
"core-js": "^3.15.2",
|
||||
|
|
|
@ -4141,6 +4141,11 @@ chokidar@^3.5.2, chokidar@^3.5.3:
|
|||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
chromatism@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/chromatism/-/chromatism-3.0.0.tgz#a7249d353c1e4f3577e444ac41171c4e2e624b12"
|
||||
integrity sha512-slVGC45odKFB6KzD/hpXP8XgS/Y+x72X1ckAhxU/9YZecCy8VwCJUSZsn0O4gQUwaTogun6IfrSiK3YuQaADFw==
|
||||
|
||||
chrome-trace-event@^1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
|
||||
|
|
Ładowanie…
Reference in New Issue