consensys-ui
Version:
Consensys UI component library and design system
215 lines (198 loc) • 6.42 kB
text/typescript
import { Config as TailwindConfig } from 'tailwindcss';
import plugin from 'tailwindcss/plugin.js';
import tailwindcssAnimate from 'tailwindcss-animate';
import {
generateColorCssVars,
generateThemeCssVars,
generateShadowCssVars,
generateConfig,
} from "./utils";
import _ from "lodash";
import {
Config,
ConfigColorShades,
ConfigTheme,
ConfigThemes,
CssVariableRecord,
UserConfig
} from "./types";
import { COLOR_MODES, DEFAULT_THEME } from "./constants";
import rnrPreset from './rnr.config';
import type { CSSRuleObject } from 'tailwindcss/types/config';
const getThemeColorKeys = (themes: ConfigThemes): string[] => {
return _.uniq(_.flatMap(Object.values(themes), (theme: ConfigTheme) => {
const colors = theme.colors;
const mergedTheme = _.merge(
{},
_.omit(colors, [COLOR_MODES.Light, COLOR_MODES.Dark]),
colors[COLOR_MODES.Light] || {},
colors[COLOR_MODES.Dark] || {}
);
return Object.keys(mergedTheme);
}));
};
const defineCssVars = (themes: ConfigThemes) =>
plugin(({ addBase }) => {
const vars: Record<string, CssVariableRecord> = {};
Object.entries(themes).forEach(([themeName, theme]) => {
const lightClassName =
themeName === DEFAULT_THEME ? `.${COLOR_MODES.Light}` : `.${themeName}.${COLOR_MODES.Light}`;
const darkClassName =
themeName === DEFAULT_THEME ? `.${COLOR_MODES.Dark}` : `.${themeName}.${COLOR_MODES.Dark}`;
// Generate color variables
const lightVars = generateThemeCssVars(theme.colors.light);
const darkVars = generateThemeCssVars(theme.colors.dark);
// Generate shadow variables if they exist
if (theme.boxShadow) {
Object.assign(lightVars, generateShadowCssVars(theme.boxShadow.light));
Object.assign(darkVars, generateShadowCssVars(theme.boxShadow.dark));
}
vars[lightClassName] = lightVars;
vars[darkClassName] = darkVars;
});
// Convert the vars record into a CSSRuleObject
const cssRules: CSSRuleObject = Object.entries(vars).reduce((acc, [selector, variables]) => ({
...acc,
[selector]: variables
}), {});
addBase(cssRules);
});
const assignCssVars = (themes: ConfigThemes): Record<string, ConfigColorShades> => {
return Object.fromEntries(
getThemeColorKeys(themes).map(key => [key, generateColorCssVars(key)])
);
};
const assignShadowVars = (themes: ConfigThemes): Record<string, string> => {
const defaultTheme = themes[DEFAULT_THEME];
if (!defaultTheme?.boxShadow?.light) return {};
return Object.fromEntries(
Object.keys(defaultTheme.boxShadow.light).map(key => [
key,
`var(--shadow-${key})`
])
);
};
const pxToRem = (px: number, base: number = 16) => `${px / base}rem`;
export const tailwindPreset = (userConfig: UserConfig): TailwindConfig => {
const config = generateConfig(userConfig);
return {
darkMode: 'class',
content: [],
presets: [
rnrPreset,
],
plugins: [
defineCssVars(config.themes),
tailwindcssAnimate,
],
theme: {
extend: {
colors: assignCssVars(config.themes),
boxShadow: assignShadowVars(config.themes),
spacing: {
0: '0rem',
'0.5': '0.125rem',
1: '0.25rem',
'1.5': '0.375rem',
2: '0.5rem',
'2.5': '0.625rem',
3: '0.75rem',
'3.5': '0.875rem',
4: '1rem',
5: '1.25rem',
6: '1.5rem',
7: '1.75rem',
8: '2rem',
10: '2.5rem',
12: '3rem',
14: '3.5rem',
16: '4rem',
18: '4.5rem',
20: '5rem',
24: '6rem',
28: '7rem',
32: '8rem',
36: '9rem',
40: '10rem',
},
borderRadius: {
0: '0',
1: pxToRem(2),
2: pxToRem(4),
3: pxToRem(6),
4: pxToRem(8),
5: pxToRem(10),
6: pxToRem(12),
7: pxToRem(14),
8: pxToRem(16),
'full': '9999px',
},
fontFamily: {
inter: ['"Inter"', 'sans-serif'],
roboto: ['"Roboto"', 'sans-serif'],
robotoCondensed: ['"Roboto Condensed"', 'sans-serif'],
robotoSlab: ['"Roboto Slab"', 'serif'],
libreFranklin: ['"Libre Franklin"', 'sans-serif'],
},
fontWeight: {
light: '300',
regular: '400',
medium: '500',
bold: '700',
},
lineHeight: {
'tight': '1.25',
'normal': '1.5',
'loose': '2',
},
fontSize: {
// font
2: '0.5rem',
'2.5': '0.625rem',
3: '0.75rem',
'3.5': '0.875rem',
4: '1rem',
'4.5': '1.125rem',
5: '1.25rem',
'5.5': '1.375rem',
6: '1.5rem',
7: '1.75rem',
8: '2rem',
10: '2.5rem',
12: '3rem',
14: '3.5rem',
16: '4rem',
// text
'xl': ['1.25rem', { lineHeight: '1.875rem', fontWeight: '400' }],
'lg': ['1.125rem', { lineHeight: '1.6875rem', fontWeight: '400' }],
'base': ['1rem', { lineHeight: '1.5rem', fontWeight: '400' }],
'sm': ['0.875rem', { lineHeight: '1.3125rem', fontWeight: '400' }],
'xs': ['0.75rem', { lineHeight: '1.125rem', fontWeight: '400' }],
// heading
'h1': ['4rem', { lineHeight: '5rem', fontWeight: '700' }],
'h2': ['3rem', { lineHeight: '3.75rem', fontWeight: '700' }],
'h3': ['2rem', { lineHeight: '2.5rem', fontWeight: '700' }],
'h4': ['1.75rem', { lineHeight: '2.1875rem', fontWeight: '700' }],
'h5': ['1.5rem', { lineHeight: '1.875rem', fontWeight: '700' }],
'h6': ['1.25rem', { lineHeight: '1.5625rem', fontWeight: '700' }],
},
animation: {
'spin-normal': 'spin 2s linear infinite',
'spin-slow': 'spin 4s linear infinite',
'spin-fast': 'spin 1s linear infinite',
'spin-reverse': 'spin 2s linear infinite reverse',
},
keyframes: {
spin: {
'0%': { transform: 'rotate(0deg)' },
'100%': { transform: 'rotate(360deg)' },
},
},
},
},
safelist: [
...Object.values(COLOR_MODES),
...Object.keys(config.themes),
],
};
};