Normalize Tailwind colors from SoapboxConfig
This commit is contained in:
parent
7fc4950387
commit
fff580f053
6 changed files with 117 additions and 62 deletions
|
@ -41,7 +41,47 @@ export const makeDefaultConfig = features => {
|
||||||
banner: '',
|
banner: '',
|
||||||
brandColor: '', // Empty
|
brandColor: '', // Empty
|
||||||
accentColor: '',
|
accentColor: '',
|
||||||
colors: ImmutableMap(),
|
colors: ImmutableMap({
|
||||||
|
gray: ImmutableMap({
|
||||||
|
50: '#f9fafb',
|
||||||
|
100: '#f3f4f6',
|
||||||
|
200: '#e5e7eb',
|
||||||
|
300: '#d1d5db',
|
||||||
|
400: '#9ca3af',
|
||||||
|
500: '#6b7280',
|
||||||
|
600: '#4b5563',
|
||||||
|
700: '#374151',
|
||||||
|
800: '#1f2937',
|
||||||
|
900: '#111827',
|
||||||
|
}),
|
||||||
|
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',
|
||||||
|
}),
|
||||||
|
'gradient-purple': '#b8a3f9',
|
||||||
|
'gradient-blue': '#9bd5ff',
|
||||||
|
'sea-blue': '#2feecc',
|
||||||
|
}),
|
||||||
customCss: ImmutableList(),
|
customCss: ImmutableList(),
|
||||||
promoPanel: ImmutableMap({
|
promoPanel: ImmutableMap({
|
||||||
items: ImmutableList(),
|
items: ImmutableList(),
|
||||||
|
@ -73,7 +113,8 @@ export const getSoapboxConfig = createSelector([
|
||||||
state => state.get('soapbox'),
|
state => state.get('soapbox'),
|
||||||
state => getFeatures(state.get('instance')),
|
state => getFeatures(state.get('instance')),
|
||||||
], (soapbox, features) => {
|
], (soapbox, features) => {
|
||||||
return makeDefaultConfig(features).merge(soapbox);
|
const defaultConfig = makeDefaultConfig(features);
|
||||||
|
return soapbox.mergeDeepWith((o, n) => o || n, defaultConfig);
|
||||||
});
|
});
|
||||||
|
|
||||||
export function rememberSoapboxConfig(host) {
|
export function rememberSoapboxConfig(host) {
|
||||||
|
|
|
@ -25,7 +25,7 @@ import { createGlobals } from 'soapbox/globals';
|
||||||
import messages from 'soapbox/locales/messages';
|
import messages from 'soapbox/locales/messages';
|
||||||
import { makeGetAccount } from 'soapbox/selectors';
|
import { makeGetAccount } from 'soapbox/selectors';
|
||||||
import SoapboxPropTypes from 'soapbox/utils/soapbox_prop_types';
|
import SoapboxPropTypes from 'soapbox/utils/soapbox_prop_types';
|
||||||
import { themeColorsToCSS } from 'soapbox/utils/theme';
|
import { generateThemeCss } from 'soapbox/utils/theme';
|
||||||
|
|
||||||
import { INTRODUCTION_VERSION } from '../actions/onboarding';
|
import { INTRODUCTION_VERSION } from '../actions/onboarding';
|
||||||
import { preload } from '../actions/preload';
|
import { preload } from '../actions/preload';
|
||||||
|
@ -84,7 +84,7 @@ const mapStateToProps = (state) => {
|
||||||
dyslexicFont: settings.get('dyslexicFont'),
|
dyslexicFont: settings.get('dyslexicFont'),
|
||||||
demetricator: settings.get('demetricator'),
|
demetricator: settings.get('demetricator'),
|
||||||
locale: validLocale(locale) ? locale : 'en',
|
locale: validLocale(locale) ? locale : 'en',
|
||||||
themeCss: themeColorsToCSS(soapboxConfig.get('brandColor') || '#0482d8', soapboxConfig.get('accentColor', '')),
|
themeCss: generateThemeCss(soapboxConfig),
|
||||||
brandColor: soapboxConfig.get('brandColor'),
|
brandColor: soapboxConfig.get('brandColor'),
|
||||||
themeMode: settings.get('themeMode'),
|
themeMode: settings.get('themeMode'),
|
||||||
singleUserMode,
|
singleUserMode,
|
||||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
|
||||||
import { defaultSettings } from 'soapbox/actions/settings';
|
import { defaultSettings } from 'soapbox/actions/settings';
|
||||||
import { themeColorsToCSS } from 'soapbox/utils/theme';
|
import { generateThemeCss } from 'soapbox/utils/theme';
|
||||||
|
|
||||||
export default function SitePreview({ soapbox }) {
|
export default function SitePreview({ soapbox }) {
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ export default function SitePreview({ soapbox }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={bodyClass}>
|
<div className={bodyClass}>
|
||||||
<style>{`.site-preview {${themeColorsToCSS(soapbox.get('brandColor'), soapbox.get('accentColor'))}}`}</style>
|
<style>{`.site-preview {${generateThemeCss(soapbox)}}`}</style>
|
||||||
<div className='app-holder'>
|
<div className='app-holder'>
|
||||||
<div>
|
<div>
|
||||||
<div className='ui'>
|
<div className='ui'>
|
||||||
|
|
|
@ -3,21 +3,31 @@ import { Map as ImmutableMap } from 'immutable';
|
||||||
import { toTailwind, fromLegacyColors, expandPalette } from '../tailwind';
|
import { toTailwind, fromLegacyColors, expandPalette } from '../tailwind';
|
||||||
|
|
||||||
describe('toTailwind()', () => {
|
describe('toTailwind()', () => {
|
||||||
|
it('handles empty Soapbox config', () => {
|
||||||
|
const soapboxConfig = ImmutableMap();
|
||||||
|
const result = toTailwind(soapboxConfig);
|
||||||
|
const expected = ImmutableMap({ colors: ImmutableMap() });
|
||||||
|
expect(result).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
it('converts brandColor into a Tailwind color palette', () => {
|
it('converts brandColor into a Tailwind color palette', () => {
|
||||||
const soapboxConfig = ImmutableMap({ brandColor: '#0482d8' });
|
const soapboxConfig = ImmutableMap({ brandColor: '#0482d8' });
|
||||||
|
|
||||||
const expected = {
|
const expected = {
|
||||||
primary: {
|
brandColor: '#0482d8',
|
||||||
50: '#f2f9fd',
|
colors: {
|
||||||
100: '#e6f3fb',
|
primary: {
|
||||||
200: '#c0e0f5',
|
50: '#f2f9fd',
|
||||||
300: '#9bcdef',
|
100: '#e6f3fb',
|
||||||
400: '#4fa8e4',
|
200: '#c0e0f5',
|
||||||
500: '#0482d8',
|
300: '#9bcdef',
|
||||||
600: '#0475c2',
|
400: '#4fa8e4',
|
||||||
700: '#0362a2',
|
500: '#0482d8',
|
||||||
800: '#024e82',
|
600: '#0475c2',
|
||||||
900: '#02406a',
|
700: '#0362a2',
|
||||||
|
800: '#024e82',
|
||||||
|
900: '#02406a',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,17 +46,20 @@ describe('toTailwind()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const expected = {
|
const expected = {
|
||||||
primary: {
|
brandColor: '#0482d8',
|
||||||
50: '#f2f9fd',
|
colors: {
|
||||||
100: '#e6f3fb',
|
primary: {
|
||||||
200: '#c0e0f5',
|
50: '#f2f9fd',
|
||||||
300: '#ff0000', // <--
|
100: '#e6f3fb',
|
||||||
400: '#4fa8e4',
|
200: '#c0e0f5',
|
||||||
500: '#0482d8',
|
300: '#ff0000', // <--
|
||||||
600: '#0475c2',
|
400: '#4fa8e4',
|
||||||
700: '#0362a2',
|
500: '#0482d8',
|
||||||
800: '#024e82',
|
600: '#0475c2',
|
||||||
900: '#02406a',
|
700: '#0362a2',
|
||||||
|
800: '#024e82',
|
||||||
|
900: '#02406a',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -72,6 +85,19 @@ describe('fromLegacyColors()', () => {
|
||||||
800: '#024e82',
|
800: '#024e82',
|
||||||
900: '#02406a',
|
900: '#02406a',
|
||||||
},
|
},
|
||||||
|
// Accent color is generated from brandColor
|
||||||
|
accent: {
|
||||||
|
50: '#f3fbfd',
|
||||||
|
100: '#e7f7fa',
|
||||||
|
200: '#c3ecf4',
|
||||||
|
300: '#9fe1ed',
|
||||||
|
400: '#58cadf',
|
||||||
|
500: '#10b3d1',
|
||||||
|
600: '#0ea1bc',
|
||||||
|
700: '#0c869d',
|
||||||
|
800: '#0a6b7d',
|
||||||
|
900: '#085866',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = fromLegacyColors(soapboxConfig);
|
const result = fromLegacyColors(soapboxConfig);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||||
|
|
||||||
import tintify from 'soapbox/utils/colors';
|
import tintify from 'soapbox/utils/colors';
|
||||||
|
import { generateAccent } from 'soapbox/utils/theme';
|
||||||
|
|
||||||
import type { TailwindColorPalette } from 'soapbox/types/colors';
|
import type { TailwindColorPalette } from 'soapbox/types/colors';
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@ export const expandPalette = (palette: TailwindColorPalette): TailwindColorPalet
|
||||||
// Conditionally handle hex color and Tailwind color object
|
// Conditionally handle hex color and Tailwind color object
|
||||||
if (typeof color === 'string' && isHex(color)) {
|
if (typeof color === 'string' && isHex(color)) {
|
||||||
result[colorName] = tintify(color);
|
result[colorName] = tintify(color);
|
||||||
} else if (typeof color === 'object') {
|
} else if (color && typeof color === 'object') {
|
||||||
result[colorName] = color;
|
result[colorName] = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,18 +28,26 @@ export const expandPalette = (palette: TailwindColorPalette): TailwindColorPalet
|
||||||
}, {});
|
}, {});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Generate accent color only if brandColor is present
|
||||||
|
const maybeGenerateAccentColor = (brandColor: any): string | null => {
|
||||||
|
return isHex(brandColor) ? generateAccent(brandColor) : null;
|
||||||
|
};
|
||||||
|
|
||||||
/** Build a color object from legacy colors */
|
/** Build a color object from legacy colors */
|
||||||
export const fromLegacyColors = (soapboxConfig: SoapboxConfig): TailwindColorPalette => {
|
export const fromLegacyColors = (soapboxConfig: SoapboxConfig): TailwindColorPalette => {
|
||||||
|
const brandColor = soapboxConfig.get('brandColor');
|
||||||
|
const accentColor = soapboxConfig.get('accentColor');
|
||||||
|
|
||||||
return expandPalette({
|
return expandPalette({
|
||||||
primary: soapboxConfig.get('brandColor'),
|
primary: isHex(brandColor) ? brandColor : null,
|
||||||
accent: soapboxConfig.get('accentColor'),
|
accent: isHex(accentColor) ? accentColor : maybeGenerateAccentColor(brandColor),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Convert Soapbox Config into Tailwind colors */
|
/** Convert Soapbox Config into Tailwind colors */
|
||||||
export const toTailwind = (soapboxConfig: SoapboxConfig): SoapboxColors => {
|
export const toTailwind = (soapboxConfig: SoapboxConfig): SoapboxConfig => {
|
||||||
const colors: SoapboxColors = ImmutableMap(soapboxConfig.get('colors'));
|
const colors: SoapboxColors = ImmutableMap(soapboxConfig.get('colors'));
|
||||||
const legacyColors: SoapboxColors = ImmutableMap(fromJS(fromLegacyColors(soapboxConfig)));
|
const legacyColors: SoapboxColors = ImmutableMap(fromJS(fromLegacyColors(soapboxConfig)));
|
||||||
|
|
||||||
return legacyColors.mergeDeep(colors);
|
return soapboxConfig.set('colors', legacyColors.mergeDeep(colors));
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import tintify, { hexToRgb } from './colors';
|
import { hexToRgb } from './colors';
|
||||||
|
import { toTailwind } from './tailwind';
|
||||||
|
|
||||||
import type { Rgb, Hsl, TailwindColorPalette } from 'soapbox/types/colors';
|
import type { Map as ImmutableMap } from 'immutable';
|
||||||
|
import type { Rgb, Hsl, TailwindColorPalette, TailwindColorObject } from 'soapbox/types/colors';
|
||||||
|
|
||||||
// Taken from chromatism.js
|
// Taken from chromatism.js
|
||||||
// https://github.com/graypegg/chromatism/blob/master/src/conversions/rgb.js
|
// https://github.com/graypegg/chromatism/blob/master/src/conversions/rgb.js
|
||||||
|
@ -59,9 +61,7 @@ function hslToHex(color: Hsl): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate accent color from brand color
|
// Generate accent color from brand color
|
||||||
const generateAccent = (brandColor: string): string => {
|
export const generateAccent = (brandColor: string): string => {
|
||||||
console.log(brandColor);
|
|
||||||
console.log(hexToRgb(brandColor));
|
|
||||||
const { h } = rgbToHsl(hexToRgb(brandColor));
|
const { h } = rgbToHsl(hexToRgb(brandColor));
|
||||||
return hslToHex({ h: h - 15, s: 86, l: 44 });
|
return hslToHex({ h: h - 15, s: 86, l: 44 });
|
||||||
};
|
};
|
||||||
|
@ -81,7 +81,7 @@ const parseShades = (obj: Record<string, any>, color: string, shades: Record<str
|
||||||
// Convert colors as CSS variables
|
// Convert colors as CSS variables
|
||||||
const parseColors = (colors: TailwindColorPalette): TailwindColorPalette => {
|
const parseColors = (colors: TailwindColorPalette): TailwindColorPalette => {
|
||||||
return Object.keys(colors).reduce((obj, color) => {
|
return Object.keys(colors).reduce((obj, color) => {
|
||||||
parseShades(obj, color, colors[color]);
|
parseShades(obj, color, colors[color] as TailwindColorObject);
|
||||||
return obj;
|
return obj;
|
||||||
}, {});
|
}, {});
|
||||||
};
|
};
|
||||||
|
@ -93,27 +93,6 @@ export const colorsToCss = (colors: TailwindColorPalette): string => {
|
||||||
}, '');
|
}, '');
|
||||||
};
|
};
|
||||||
|
|
||||||
const legacyColorsToTailwind = (brandColor: string, accentColor: string): TailwindColorPalette => {
|
export const generateThemeCss = (soapboxConfig: ImmutableMap<string, any>): string => {
|
||||||
return {
|
return colorsToCss(toTailwind(soapboxConfig).get('colors').toJS() as TailwindColorPalette);
|
||||||
primary: tintify(brandColor),
|
|
||||||
accent: tintify(accentColor ? accentColor : generateAccent(brandColor)),
|
|
||||||
gray: {
|
|
||||||
50: '#f9fafb',
|
|
||||||
100: '#f3f4f6',
|
|
||||||
200: '#e5e7eb',
|
|
||||||
300: '#d1d5db',
|
|
||||||
400: '#9ca3af',
|
|
||||||
500: '#6b7280',
|
|
||||||
600: '#4b5563',
|
|
||||||
700: '#374151',
|
|
||||||
800: '#1f2937',
|
|
||||||
900: '#111827',
|
|
||||||
},
|
|
||||||
'sea-blue': '#2feecc',
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const themeColorsToCSS = (brandColor: string, accentColor: string): string => {
|
|
||||||
const colors = legacyColorsToTailwind(brandColor, accentColor);
|
|
||||||
return colorsToCss(colors);
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue