Skip to content

Commit

Permalink
chore: refactore core lib code
Browse files Browse the repository at this point in the history
  • Loading branch information
fluid-design-io committed Jun 24, 2024
1 parent b4d427a commit 54b8e08
Show file tree
Hide file tree
Showing 14 changed files with 857 additions and 31,173 deletions.
33 changes: 11 additions & 22 deletions apps/web/lib/animation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,13 @@
* @param options
* @returns
*/
export const textAnimation = (
shouldReduceMotion: boolean,
animationDelay: number,
options: {
performance: "low" | "medium" | "high";
} = { performance: "high" },
) => ({
initial: shouldReduceMotion
? { opacity: 0 }
: {
opacity: 0,
...(options.performance === "high" && {
filter: "blur(0.35rem)",
}),
},
export const textAnimation = (shouldReduceMotion: boolean, animationDelay: number) => ({
animate: shouldReduceMotion
? { opacity: 1, transition: { delay: 0.2 } }
: {
filter: 'blur(0rem)',
opacity: 1,
...(options.performance === "high" && {
filter: "blur(0rem)",
}),

transition: {
delay: animationDelay,
duration: 0.44 + animationDelay * 1.2,
Expand All @@ -35,11 +20,15 @@ export const textAnimation = (
exit: shouldReduceMotion
? { opacity: 0 }
: {
filter: 'blur(0.35rem)',
opacity: 0,
...(options.performance === "high" && {
filter: "blur(0.35rem)",
}),
transition: { delay: animationDelay * 0.8 },
},
initial: shouldReduceMotion
? { opacity: 0 }
: {
filter: 'blur(0.35rem)',
opacity: 0,
},
// viewport: { once: true },
});
})
149 changes: 65 additions & 84 deletions apps/web/lib/colorCalculator.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { COLOR_LENGTH } from "./colorStepMap";
import { findClosestColors } from "./findColosestHues";
import { lightnessFormula } from "./lightnessFormula";
import { saturationsFormula } from "./saturationsFormula";
import { BaseColorTypes, ColorMode, ColorValue, RawColor } from "@/types/app";
import { colorHelper } from "./colorHelper";
import tinycolor from "tinycolor2";
import { formatHsl, converter } from "culori";
import { BaseColorTypes, ColorMode, ColorValue, RawColor } from '@/types/app'
import { converter, formatHsl } from 'culori'
import tinycolor from 'tinycolor2'

import { colorHelper } from './colorHelper'
import { COLOR_LENGTH } from './colorStepMap'
import { findClosestColors } from './findColosestHues'
import { lightnessFormula } from './lightnessFormula'
import { saturationsFormula } from './saturationsFormula'

const calculateLightness = (
inputHue: number,
Expand All @@ -14,57 +15,43 @@ const calculateLightness = (
formulatRightLightness: (x: number) => number,
colorLeftRatio: number,
colorRightRatio: number,
inputLightness: number,
inputLightness: number
) => {
let res =
(formulatLeftLightness(step) * colorLeftRatio +
formulatRightLightness(step) * colorRightRatio) *
0.97 +
inputLightness * 0.03 * 100;
(formulatLeftLightness(step) * colorLeftRatio + formulatRightLightness(step) * colorRightRatio) * 0.97 +
inputLightness * 0.03 * 100
if (step === 9) {
// if inputHue is between green and purple, we will limit the lightness * 0.95
if (inputHue > 70 && inputHue < 300) {
res *= 0.95;
res *= 0.95
}
// if inputHue is between blue and violet, we will limit the lightness * 0.95 again
if (inputHue > 200 && inputHue < 260) {
res *= 0.95;
res *= 0.95
}
}
if (step === 10) {
// if inputHue is between green and purple, we will limit the lightness * 0.9
if (inputHue > 70 && inputHue < 300) {
res *= 0.9;
res *= 0.9
}
// if inputHue is between blue and violet, we will limit the lightness * 0.9 again
if (inputHue > 200 && inputHue < 260) {
res *= 0.9;
res *= 0.9
}
}

return res;
};
return res
}

export const getUnionFormula = (
inputHue: number,
inputSaturation: number,
inputLightness: number,
) => {
const [
{ color: colorLeftName, ratio: colorLeftRatio },
{ color: colorRightName, ratio: colorRightRatio },
] = findClosestColors(inputHue);
const formulaLeftSaturation = saturationsFormula[colorLeftName];
const formulaRightSaturation = saturationsFormula[colorRightName];
const formulatLeftLightness = lightnessFormula[colorLeftName];
const formulatRightLightness = lightnessFormula[colorRightName];
export const getUnionFormula = (inputHue: number, inputSaturation: number, inputLightness: number) => {
const [{ color: colorLeftName, ratio: colorLeftRatio }, { color: colorRightName, ratio: colorRightRatio }] =
findClosestColors(inputHue)
const formulaLeftSaturation = saturationsFormula[colorLeftName]
const formulaRightSaturation = saturationsFormula[colorRightName]
const formulatLeftLightness = lightnessFormula[colorLeftName]
const formulatRightLightness = lightnessFormula[colorRightName]
return (step: number) => ({
// we will take 90% of inputSaturation and 10% of the other color saturation
saturation:
(formulaLeftSaturation(step) * colorLeftRatio +
formulaRightSaturation(step) * colorRightRatio) *
0.1 +
inputSaturation * 0.9 * 100,
// we will take 3% of inputLightness and 97% of the other color lightness
lightness: calculateLightness(
inputHue,
Expand All @@ -73,65 +60,59 @@ export const getUnionFormula = (
formulatRightLightness,
colorLeftRatio,
colorRightRatio,
inputLightness,
inputLightness
),
});
};
// we will take 88% of inputSaturation and 12% of the other color saturation
saturation:
(formulaLeftSaturation(step) * colorLeftRatio + formulaRightSaturation(step) * colorRightRatio) * 0.12 +
inputSaturation * 0.88 * 100,
})
}

export const colorStep = (i) => (i === 0 ? 50 : i === 10 ? 950 : i * 100);
export const colorStep = (i: number) => (i === 0 ? 50 : i === 10 ? 950 : i * 100)

export const generateColorPalette = ({
color,
type,
colorMode,
}: {
color: RawColor;
type: BaseColorTypes | "gray";
colorMode: ColorMode;
}): ColorValue[] =>
export const generateColorPalette = ({ color, type }: { color: RawColor; type: BaseColorTypes }): ColorValue[] =>
Array.from({ length: COLOR_LENGTH }, (_, i) => {
const rawColor = tinycolor(color);
let calculatedColor = rawColor;
const step = i;
const sat = rawColor.toHsl().s;
const lig = rawColor.toHsl().l;
if (type === "gray") {
const oklchConverter = converter("oklch");
const okhslConverter = converter("okhsl");
const okhslColor = okhslConverter({ ...color, mode: "hsl" });
const oklschColor = oklchConverter({ ...color, mode: "hsl" });
let { h, s } = okhslColor;
let { l } = oklschColor;
l =
(COLOR_LENGTH - 1 - i) * ((1 / COLOR_LENGTH) * 0.95) +
1 / COLOR_LENGTH / 2;
s = 0.02 + sat * 0.25;
calculatedColor = tinycolor(formatHsl({ l, s, h, mode: "okhsl" }));
const rawColor = tinycolor(color)
let calculatedColor = rawColor
const step = i
const sat = rawColor.toHsl().s
const lig = rawColor.toHsl().l
if (type === 'gray') {
const oklchConverter = converter('oklch')
const okhslConverter = converter('okhsl')
const okhslColor = okhslConverter({ ...color, mode: 'hsl' })
const oklschColor = oklchConverter({ ...color, mode: 'hsl' })
let { h, s } = okhslColor
let { l } = oklschColor
const lInfluence = lig / 50 // 2% of the lightness based on the input lightness
l = (COLOR_LENGTH - 1 - i) * (1 / COLOR_LENGTH) + lInfluence + 1 / COLOR_LENGTH / 2
console.log(`l: ${l}, lig: ${lig}`)
s = 0.01 + sat * 0.25
calculatedColor = tinycolor(formatHsl({ h, l, mode: 'okhsl', s }))
} else {
let hue = Math.round(rawColor.toHsl().h * 10) / 10;
let hue = Math.round(rawColor.toHsl().h * 10) / 10
// if hue is Nan, set it to 0
if (isNaN(hue)) {
const lch = calculatedColor.toLch();
const lch = calculatedColor.toLch()
calculatedColor = tinycolor({
l: (COLOR_LENGTH - 1 - i) * 8.85 + 5,
c: lch.c,
h: lch.h,
});
l: (COLOR_LENGTH - 1 - i) * 8.85 + 5,
})
} else {
hue === 360 ? (hue = 0.001) : hue;
hue === 0 ? (hue = 0.001) : hue;
// const saturation = calculateSaturation(hue, sat, COLOR_LENGTH - i);
// const luminescence = getColorLuminescence(hue, lum, COLOR_LENGTH - i);
const formula = getUnionFormula(hue, sat, lig);
const { saturation, lightness } = formula(step);
const colorString = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
calculatedColor = tinycolor(colorString);
hue === 360 ? (hue = 0.001) : hue
hue === 0 ? (hue = 0.001) : hue
const formula = getUnionFormula(hue, sat, lig)
const { lightness, saturation } = formula(step)
const colorString = `hsl(${hue}, ${saturation}%, ${lightness}%)`
calculatedColor = tinycolor(colorString)
}
}
const convertedColor = colorHelper.toColorMode(calculatedColor, colorMode);
const convertedColor = colorHelper.toColorMode(calculatedColor, ColorMode.HEX)
return {
step: colorStep(step),
color: convertedColor,
raw: tinycolor(convertedColor).toHsl() as RawColor,
};
});
step: colorStep(step),
}
})
84 changes: 46 additions & 38 deletions apps/web/lib/colorHelper.ts
Original file line number Diff line number Diff line change
@@ -1,65 +1,73 @@
import { BaseColors, ColorMode, RGB, RawColor } from "@/types/app";
import tinycolor from "tinycolor2";
import { BaseColors, ColorMode, ColorOptions, RGB, RawColor } from '@/types/app'
import tinycolor from 'tinycolor2'

const toHex = (color: string | RawColor): string =>
tinycolor(color).toHexString();
const toRgba = (color: string | RawColor): string =>
tinycolor(color).toRgbString();
const toHsla = (color: string | RawColor): string =>
tinycolor(color).toHslString();
const toRgb = (color: string | RawColor): RGB => tinycolor(color).toRgb();
const toHex = (color: RawColor | string): string => tinycolor(color).toHexString()
const toRgba = (color: RawColor | string): string => tinycolor(color).toRgbString()
const toHsla = (color: RawColor | string): string => tinycolor(color).toHslString()
const toRgb = (color: RawColor | string): RGB => tinycolor(color).toRgb()

const toColorMode = (color: any, mode: ColorMode): string => {
if (!tinycolor(color).isValid) return "#000";
if (!tinycolor(color).isValid) return '#000'
switch (mode) {
case ColorMode.HEX:
return toHex(color);
return toHex(color)
case ColorMode.RGB:
return toRgba(color);
return toRgba(color)
case ColorMode.HSL:
return toHsla(color);
return toHsla(color)
}
};
}

/**
* Returns a color that is suitable for use as a foreground color
* @param color
*/
const toForeground = (color: string | RawColor): string => {
const hsl = tinycolor(color).toHsl();
const { h, s, l } = hsl;
const lRounded = Math.round(l * 100);
const toForeground = (color: RawColor | string): string => {
const hsl = tinycolor(color).toHsl()
const { h, l, s } = hsl
const lRounded = Math.round(l * 100)
if (lRounded > 50) {
return tinycolor(color).darken(35).toHslString();
return tinycolor(color).darken(35).toHslString()
} else {
return tinycolor(color).lighten(35).toHslString();
return tinycolor(color).lighten(35).toHslString()
}
};
}

const toRaw = (color: string): RawColor => {
const { h, s, l, a } = tinycolor(color).toHsl();
return { h, s, l, a };
};
const { a, h, l, s } = tinycolor(color).toHsl()
return { a, h, l, s }
}

const colorStringToBaseColors = (
colorString: string,
): Omit<BaseColors, "gray"> => {
const colors = colorString.split(",");
const colorStringToBaseColors = (colorString: string): Omit<BaseColors, 'gray'> => {
const colors = colorString.split(',')
const baseColors = {
accent: colorHelper.toRaw(colors[2]),
primary: colorHelper.toRaw(colors[0]),
secondary: colorHelper.toRaw(colors[1]),
accent: colorHelper.toRaw(colors[2]),
};
return baseColors;
};
}
return baseColors
}

export const isValidBaseColorType = (color: string): boolean => ['accent', 'primary', 'secondary'].includes(color)

export const isValidBaseColors = (colors: ColorOptions): boolean => {
const isKeyValid = Object.keys(colors).every(isValidBaseColorType)
if (!isKeyValid) return false
return Object.values(colors).every((color) => tinycolor(color).isValid())
}

export const areSearchParamColorsValid = (primary?: string, secondary?: string, accent?: string) => {
if (!primary || !secondary || !accent) return false
return tinycolor(primary).isValid() && tinycolor(secondary).isValid() && tinycolor(accent).isValid()
}

export const colorHelper = {
toHex,
toRgba,
toRgb,
toHsla,
colorStringToBaseColors,
toColorMode,
toForeground,
toHex,
toHsla,
toRaw,
colorStringToBaseColors,
};
toRgb,
toRgba,
}
8 changes: 6 additions & 2 deletions apps/web/lib/colorStepMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ export const colorStepMap = {
8: 800,
9: 900,
10: 950,
};
}

export const COLOR_LENGTH = Object.keys(colorStepMap).length;
export type ColorStep = keyof typeof colorStepMap
export type ColorSteps = ColorStep[]
export type ColorValue = (typeof colorStepMap)[ColorStep]

export const COLOR_LENGTH = Object.keys(colorStepMap).length
Loading

0 comments on commit 54b8e08

Please sign in to comment.