import { theme as chakraTheme } from "@chakra-ui/core"; import chroma from "chroma-js"; const alphaColors = color => ({ 900: chroma(color) .alpha(0.92) .css(), 800: chroma(color) .alpha(0.8) .css(), 700: chroma(color) .alpha(0.6) .css(), 600: chroma(color) .alpha(0.48) .css(), 500: chroma(color) .alpha(0.38) .css(), 400: chroma(color) .alpha(0.24) .css(), 300: chroma(color) .alpha(0.16) .css(), 200: chroma(color) .alpha(0.12) .css(), 100: chroma(color) .alpha(0.08) .css(), 50: chroma(color) .alpha(0.04) .css() }); const generateColors = colorInput => { const colorMap = {}; const lightnessMap = [ 0.95, 0.85, 0.75, 0.65, 0.55, 0.45, 0.35, 0.25, 0.15, 0.05 ]; const saturationMap = [0.32, 0.16, 0.08, 0.04, 0, 0, 0.04, 0.08, 0.16, 0.32]; const validColor = chroma.valid(colorInput.trim()) ? chroma(colorInput.trim()) : chroma("#000"); const lightnessGoal = validColor.get("hsl.l"); const closestLightness = lightnessMap.reduce((prev, curr) => Math.abs(curr - lightnessGoal) < Math.abs(prev - lightnessGoal) ? curr : prev ); const baseColorIndex = lightnessMap.findIndex(l => l === closestLightness); const colors = lightnessMap .map(l => validColor.set("hsl.l", l)) .map(color => chroma(color)) .map((color, i) => { const saturationDelta = saturationMap[i] - saturationMap[baseColorIndex]; return saturationDelta >= 0 ? color.saturate(saturationDelta) : color.desaturate(saturationDelta * -1); }); const getColorNumber = index => (index === 0 ? 50 : index * 100); colors.map((color, i) => { const colorIndex = getColorNumber(i); colorMap[colorIndex] = color.hex(); }); return colorMap; }; const defaultBodyFonts = [ "-apple-system", "BlinkMacSystemFont", '"Segoe UI"', "Helvetica", "Arial", "sans-serif", '"Apple Color Emoji"', '"Segoe UI Emoji"', '"Segoe UI Symbol"' ]; const defaultMonoFonts = [ "SFMono-Regular", "Melno", "Monaco", "Consolas", '"Liberation Mono"', '"Courier New"', "monospace" ]; const generatePalette = palette => { const generatedPalette = {}; Object.keys(palette).map(color => { if (!["black", "white"].includes(color)) { generatedPalette[color] = generateColors(palette[color]); } else { generatedPalette[color] = palette[color]; generatedPalette[`${color}Alpha`] = alphaColors(palette[color]); } }); return generatedPalette; }; const formatFont = font => { const fontList = font.split(" "); const fontFmt = fontList.length >= 2 ? `'${fontList.join(" ")}'` : fontList.join(" "); return fontFmt; }; const importFonts = userFonts => { const [body, mono] = [defaultBodyFonts, defaultMonoFonts]; const bodyFmt = formatFont(userFonts.body); const monoFmt = formatFont(userFonts.mono); if (userFonts.body && !body.includes(bodyFmt)) { body.unshift(bodyFmt); } if (userFonts.mono && !mono.includes(monoFmt)) { mono.unshift(monoFmt); } return { body: body.join(", "), heading: body.join(", "), mono: mono.join(", ") }; }; const importColors = (userColors = {}) => { const generatedColors = generatePalette(userColors); return { transparent: "transparent", current: "currentColor", ...generatedColors }; }; const makeTheme = userTheme => ({ ...chakraTheme, colors: importColors(userTheme.colors), fonts: importFonts(userTheme.fonts) }); export { makeTheme, chakraTheme as defaultTheme };