mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-12 21:32:40 +00:00
Generate color meta, document functions and tidy.
This commit is contained in:
parent
addfcdc1f4
commit
1fcfa5d272
11 changed files with 613 additions and 648 deletions
|
@ -1,170 +0,0 @@
|
|||
// Adapted from @k-vyn/coloralgorithm
|
||||
|
||||
import bezier from "bezier-easing";
|
||||
import chroma, { Scale } from "chroma-js";
|
||||
import { Curve } from "./curves";
|
||||
import { ColorFamily, ColorProps, ColorSet } from "./types";
|
||||
|
||||
function validColor(color: string) {
|
||||
if (chroma.valid(color)) {
|
||||
return color;
|
||||
} else {
|
||||
throw new Error(`Invalid color: ${color}`);
|
||||
}
|
||||
}
|
||||
|
||||
function assignColor(scale: Scale, steps: number, step: number) {
|
||||
const color = scale(step / steps);
|
||||
const lch = color.lch();
|
||||
const rgbaArray = color.rgba();
|
||||
const hex = color.hex();
|
||||
|
||||
// Roughly calculate if a color is dark or light
|
||||
const isLight = lch[0] > 50;
|
||||
|
||||
const result = {
|
||||
step,
|
||||
hex,
|
||||
lch,
|
||||
rgbaArray,
|
||||
isLight,
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Outputs 101 colors (0-100) */
|
||||
export function generateColors(props: ColorProps, inverted: boolean) {
|
||||
const steps = 101;
|
||||
const colors: ColorSet = [];
|
||||
|
||||
const { start, middle, end } = props.color;
|
||||
|
||||
const startColor = typeof start === "string" ? validColor(start) : start;
|
||||
const middleColor = typeof middle === "string" ? validColor(middle) : middle;
|
||||
const endColor = typeof end === "string" ? validColor(end) : end;
|
||||
|
||||
// TODO: Use curve when generating colors
|
||||
|
||||
let scale: Scale;
|
||||
|
||||
if (inverted) {
|
||||
scale = chroma.scale([endColor, middleColor, startColor]).mode("lch");
|
||||
} else {
|
||||
scale = chroma.scale([startColor, middleColor, endColor]).mode("lch");
|
||||
}
|
||||
for (let i = 0; i < steps; i++) {
|
||||
const color = assignColor(scale, steps, i);
|
||||
colors.push(color);
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
export function generateColorsUsingCurve(
|
||||
startColor: string,
|
||||
endColor: string,
|
||||
curve: number[]
|
||||
) {
|
||||
const NUM_STEPS = 101;
|
||||
|
||||
const easing = bezier(curve[0], curve[1], curve[2], curve[3]);
|
||||
const curveProgress = [];
|
||||
for (let i = 0; i <= NUM_STEPS; i++) {
|
||||
curveProgress.push(easing(i / NUM_STEPS));
|
||||
}
|
||||
|
||||
const colors: chroma.Color[] = [];
|
||||
for (let i = 0; i < NUM_STEPS; i++) {
|
||||
// Use HSL as an input as it is easier to construct programatically
|
||||
// const color = chroma.hsl();
|
||||
const color = chroma.mix(startColor, endColor, curveProgress[i], "lch");
|
||||
colors.push(color);
|
||||
}
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
export function generateColors2(
|
||||
hue: {
|
||||
start: number;
|
||||
end: number;
|
||||
curve: Curve;
|
||||
},
|
||||
saturation: {
|
||||
start: number;
|
||||
end: number;
|
||||
curve: Curve;
|
||||
},
|
||||
lightness: {
|
||||
start: number;
|
||||
end: number;
|
||||
curve: Curve;
|
||||
}
|
||||
) {
|
||||
const NUM_STEPS = 9;
|
||||
|
||||
const hueEasing = bezier(
|
||||
hue.curve.value[0],
|
||||
hue.curve.value[1],
|
||||
hue.curve.value[2],
|
||||
hue.curve.value[3]
|
||||
);
|
||||
const saturationEasing = bezier(
|
||||
saturation.curve.value[0],
|
||||
saturation.curve.value[1],
|
||||
saturation.curve.value[2],
|
||||
saturation.curve.value[3]
|
||||
);
|
||||
const lightnessEasing = bezier(
|
||||
lightness.curve.value[0],
|
||||
lightness.curve.value[1],
|
||||
lightness.curve.value[2],
|
||||
lightness.curve.value[3]
|
||||
);
|
||||
|
||||
const colors: chroma.Color[] = [];
|
||||
for (let i = 0; i < NUM_STEPS; i++) {
|
||||
const hueValue =
|
||||
hueEasing(i / NUM_STEPS) * (hue.end - hue.start) + hue.start;
|
||||
const saturationValue =
|
||||
saturationEasing(i / NUM_STEPS) * (saturation.end - saturation.start) +
|
||||
saturation.start;
|
||||
const lightnessValue =
|
||||
lightnessEasing(i / NUM_STEPS) * (lightness.end - lightness.start) +
|
||||
lightness.start;
|
||||
|
||||
const color = chroma.hsl(
|
||||
hueValue,
|
||||
saturationValue / 100,
|
||||
lightnessValue / 100
|
||||
);
|
||||
colors.push(color);
|
||||
}
|
||||
|
||||
const scale = chroma.scale(colors).mode("lch");
|
||||
return scale;
|
||||
}
|
||||
|
||||
/** Generates two color ramps:
|
||||
* One for for light, and one for dark.
|
||||
* By generating two ramps, rather than two default themes, we can use the same reference palette values for tokens in components.
|
||||
*
|
||||
* Each ramp has 101 colors (0-100)
|
||||
*/
|
||||
export function generateColorSet(props: ColorProps) {
|
||||
const generatedColors = generateColors(props, false);
|
||||
const generatedInvertedColors = generateColors(props, true);
|
||||
|
||||
const colors = generatedColors.map((color) => color.hex);
|
||||
const invertedColors = generatedInvertedColors.map((color) => color.hex);
|
||||
|
||||
const result: ColorFamily = {
|
||||
name: props.name,
|
||||
colors: colors,
|
||||
invertedColors: invertedColors,
|
||||
colorsMeta: generatedColors,
|
||||
invertedMeta: generatedInvertedColors,
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
|
@ -1,175 +0,0 @@
|
|||
// Adapted from @k-vyn/coloralgorithm
|
||||
|
||||
export interface Curve {
|
||||
name: string;
|
||||
formatted_name: string;
|
||||
value: number[];
|
||||
}
|
||||
|
||||
export interface Curves {
|
||||
lightness: Curve;
|
||||
saturation: Curve;
|
||||
linear: Curve;
|
||||
easeInCubic: Curve;
|
||||
easeOutCubic: Curve;
|
||||
easeInOutCubic: Curve;
|
||||
easeInSine: Curve;
|
||||
easeOutSine: Curve;
|
||||
easeInOutSine: Curve;
|
||||
easeInQuad: Curve;
|
||||
easeOutQuad: Curve;
|
||||
easeInOutQuad: Curve;
|
||||
easeInQuart: Curve;
|
||||
easeOutQuart: Curve;
|
||||
easeInOutQuart: Curve;
|
||||
easeInQuint: Curve;
|
||||
easeOutQuint: Curve;
|
||||
easeInOutQuint: Curve;
|
||||
easeInExpo: Curve;
|
||||
easeOutExpo: Curve;
|
||||
easeInOutExpo: Curve;
|
||||
easeInCirc: Curve;
|
||||
easeOutCirc: Curve;
|
||||
easeInOutCirc: Curve;
|
||||
easeInBack: Curve;
|
||||
easeOutBack: Curve;
|
||||
easeInOutBack: Curve;
|
||||
}
|
||||
|
||||
export const curve: Curves = {
|
||||
lightness: {
|
||||
name: "nate",
|
||||
formatted_name: "Nate",
|
||||
value: [0.2, 0, 0.85, 1.1],
|
||||
},
|
||||
saturation: {
|
||||
name: "nate",
|
||||
formatted_name: "Nate",
|
||||
value: [0.67, 0.6, 0.55, 1.0],
|
||||
},
|
||||
linear: {
|
||||
name: "linear",
|
||||
formatted_name: "Linear",
|
||||
value: [0.5, 0.5, 0.5, 0.5],
|
||||
},
|
||||
easeInCubic: {
|
||||
name: "easeInCubic",
|
||||
formatted_name: "Cubic - EaseIn",
|
||||
value: [0.55, 0.055, 0.675, 0.19],
|
||||
},
|
||||
easeOutCubic: {
|
||||
name: "easeOutCubic",
|
||||
formatted_name: "Cubic - EaseOut",
|
||||
value: [0.215, 0.61, 0.355, 1],
|
||||
},
|
||||
easeInOutCubic: {
|
||||
name: "easeInOutCubic",
|
||||
formatted_name: "Cubic - EaseInOut",
|
||||
value: [0.645, 0.045, 0.355, 1],
|
||||
},
|
||||
easeInSine: {
|
||||
name: "easeInSine",
|
||||
formatted_name: "Sine - EaseIn",
|
||||
value: [0.47, 0, 0.745, 0.715],
|
||||
},
|
||||
easeOutSine: {
|
||||
name: "easeOutSine",
|
||||
formatted_name: "Sine - EaseOut",
|
||||
value: [0.39, 0.575, 0.565, 1],
|
||||
},
|
||||
easeInOutSine: {
|
||||
name: "easeInOutSine",
|
||||
formatted_name: "Sine - EaseInOut",
|
||||
value: [0.445, 0.05, 0.55, 0.95],
|
||||
},
|
||||
easeInQuad: {
|
||||
name: "easeInQuad",
|
||||
formatted_name: "Quad - EaseIn",
|
||||
value: [0.55, 0.085, 0.68, 0.53],
|
||||
},
|
||||
easeOutQuad: {
|
||||
name: "easeOutQuad",
|
||||
formatted_name: "Quad - EaseOut",
|
||||
value: [0.25, 0.46, 0.45, 0.94],
|
||||
},
|
||||
easeInOutQuad: {
|
||||
name: "easeInOutQuad",
|
||||
formatted_name: "Quad - EaseInOut",
|
||||
value: [0.455, 0.03, 0.515, 0.955],
|
||||
},
|
||||
easeInQuart: {
|
||||
name: "easeInQuart",
|
||||
formatted_name: "Quart - EaseIn",
|
||||
value: [0.895, 0.03, 0.685, 0.22],
|
||||
},
|
||||
easeOutQuart: {
|
||||
name: "easeOutQuart",
|
||||
formatted_name: "Quart - EaseOut",
|
||||
value: [0.165, 0.84, 0.44, 1],
|
||||
},
|
||||
easeInOutQuart: {
|
||||
name: "easeInOutQuart",
|
||||
formatted_name: "Quart - EaseInOut",
|
||||
value: [0.77, 0, 0.175, 1],
|
||||
},
|
||||
easeInQuint: {
|
||||
name: "easeInQuint",
|
||||
formatted_name: "Quint - EaseIn",
|
||||
value: [0.755, 0.05, 0.855, 0.06],
|
||||
},
|
||||
easeOutQuint: {
|
||||
name: "easeOutQuint",
|
||||
formatted_name: "Quint - EaseOut",
|
||||
value: [0.23, 1, 0.32, 1],
|
||||
},
|
||||
easeInOutQuint: {
|
||||
name: "easeInOutQuint",
|
||||
formatted_name: "Quint - EaseInOut",
|
||||
value: [0.86, 0, 0.07, 1],
|
||||
},
|
||||
easeInCirc: {
|
||||
name: "easeInCirc",
|
||||
formatted_name: "Circ - EaseIn",
|
||||
value: [0.6, 0.04, 0.98, 0.335],
|
||||
},
|
||||
easeOutCirc: {
|
||||
name: "easeOutCirc",
|
||||
formatted_name: "Circ - EaseOut",
|
||||
value: [0.075, 0.82, 0.165, 1],
|
||||
},
|
||||
easeInOutCirc: {
|
||||
name: "easeInOutCirc",
|
||||
formatted_name: "Circ - EaseInOut",
|
||||
value: [0.785, 0.135, 0.15, 0.86],
|
||||
},
|
||||
easeInExpo: {
|
||||
name: "easeInExpo",
|
||||
formatted_name: "Expo - EaseIn",
|
||||
value: [0.95, 0.05, 0.795, 0.035],
|
||||
},
|
||||
easeOutExpo: {
|
||||
name: "easeOutExpo",
|
||||
formatted_name: "Expo - EaseOut",
|
||||
value: [0.19, 1, 0.22, 1],
|
||||
},
|
||||
easeInOutExpo: {
|
||||
name: "easeInOutExpo",
|
||||
formatted_name: "Expo - EaseInOut",
|
||||
value: [1, 0, 0, 1],
|
||||
},
|
||||
easeInBack: {
|
||||
name: "easeInBack",
|
||||
formatted_name: "Back - EaseIn",
|
||||
value: [0.6, -0.28, 0.735, 0.045],
|
||||
},
|
||||
easeOutBack: {
|
||||
name: "easeOutBack",
|
||||
formatted_name: "Back - EaseOut",
|
||||
value: [0.175, 0.885, 0.32, 1.275],
|
||||
},
|
||||
easeInOutBack: {
|
||||
name: "easeInOutBack",
|
||||
formatted_name: "Back - EaseInOut",
|
||||
value: [0.68, -0.55, 0.265, 1.55],
|
||||
},
|
||||
};
|
11
styles/src/system/lib/convert.ts
Normal file
11
styles/src/system/lib/convert.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/** Converts a percentage scale value (0-100) to normalized scale (0-1) value. */
|
||||
export function percentageToNormalized(value: number) {
|
||||
const normalized = value / 100;
|
||||
return normalized;
|
||||
}
|
||||
|
||||
/** Converts a normalized scale (0-1) value to a percentage scale (0-100) value. */
|
||||
export function normalizedToPercetage(value: number) {
|
||||
const percentage = value * 100;
|
||||
return percentage;
|
||||
}
|
21
styles/src/system/lib/curve.ts
Normal file
21
styles/src/system/lib/curve.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import bezier from "bezier-easing";
|
||||
import { Curve } from "../ref/curves";
|
||||
|
||||
/**
|
||||
* Formats our Curve data structure into a bezier easing function.
|
||||
* @param {Curve} curve - The curve to format.
|
||||
* @param {Boolean} inverted - Whether or not to invert the curve.
|
||||
* @returns {EasingFunction} The formatted easing function.
|
||||
*/
|
||||
export function curve(curve: Curve, inverted?: Boolean) {
|
||||
if (inverted) {
|
||||
return bezier(
|
||||
curve.value[3],
|
||||
curve.value[2],
|
||||
curve.value[1],
|
||||
curve.value[0]
|
||||
);
|
||||
}
|
||||
|
||||
return bezier(curve.value[0], curve.value[1], curve.value[2], curve.value[3]);
|
||||
}
|
157
styles/src/system/lib/generate.ts
Normal file
157
styles/src/system/lib/generate.ts
Normal file
|
@ -0,0 +1,157 @@
|
|||
import bezier from "bezier-easing";
|
||||
import chroma from "chroma-js";
|
||||
import { Color, ColorFamily, ColorFamilyConfig, ColorScale } from "../types";
|
||||
import { percentageToNormalized } from "./convert";
|
||||
import { curve } from "./curve";
|
||||
|
||||
// Re-export interface in a more standard format
|
||||
export type EasingFunction = bezier.EasingFunction;
|
||||
|
||||
/**
|
||||
* Generates a color, outputs it in multiple formats, and returns a variety of useful metadata.
|
||||
*
|
||||
* @param {EasingFunction} hueEasing - An easing function for the hue component of the color.
|
||||
* @param {EasingFunction} saturationEasing - An easing function for the saturation component of the color.
|
||||
* @param {EasingFunction} lightnessEasing - An easing function for the lightness component of the color.
|
||||
* @param {ColorFamilyConfig} family - Configuration for the color family.
|
||||
* @param {number} step - The current step.
|
||||
* @param {number} steps - The total number of steps in the color scale.
|
||||
*
|
||||
* @returns {Color} The generated color, with its calculated contrast against black and white, as well as its LCH values, RGBA array, hexadecimal representation, and a flag indicating if it is light or dark.
|
||||
*/
|
||||
function generateColor(
|
||||
hueEasing: EasingFunction,
|
||||
saturationEasing: EasingFunction,
|
||||
lightnessEasing: EasingFunction,
|
||||
family: ColorFamilyConfig,
|
||||
step: number,
|
||||
steps: number
|
||||
) {
|
||||
const { hue, saturation, lightness } = family.color;
|
||||
|
||||
const stepHue = hueEasing(step / steps) * (hue.end - hue.start) + hue.start;
|
||||
const stepSaturation =
|
||||
saturationEasing(step / steps) * (saturation.end - saturation.start) +
|
||||
saturation.start;
|
||||
const stepLightness =
|
||||
lightnessEasing(step / steps) * (lightness.end - lightness.start) +
|
||||
lightness.start;
|
||||
|
||||
const color = chroma.hsl(
|
||||
stepHue,
|
||||
percentageToNormalized(stepSaturation),
|
||||
percentageToNormalized(stepLightness)
|
||||
);
|
||||
|
||||
const contrast = {
|
||||
black: {
|
||||
value: chroma.contrast(color, "black"),
|
||||
aaPass: chroma.contrast(color, "black") >= 4.5,
|
||||
aaaPass: chroma.contrast(color, "black") >= 7,
|
||||
},
|
||||
white: {
|
||||
value: chroma.contrast(color, "white"),
|
||||
aaPass: chroma.contrast(color, "white") >= 4.5,
|
||||
aaaPass: chroma.contrast(color, "white") >= 7,
|
||||
},
|
||||
};
|
||||
|
||||
const lch = color.lch();
|
||||
const rgba = color.rgba();
|
||||
const hex = color.hex();
|
||||
|
||||
const isLight = lch[0] > 50;
|
||||
|
||||
const result: Color = {
|
||||
step,
|
||||
lch,
|
||||
hex,
|
||||
rgba,
|
||||
contrast,
|
||||
isLight,
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a color scale based on a color family configuration.
|
||||
*
|
||||
* @param {ColorFamilyConfig} config - The configuration for the color family.
|
||||
* @param {Boolean} inverted - Specifies whether the color scale should be inverted or not.
|
||||
*
|
||||
* @returns {ColorScale} The generated color scale.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const colorScale = generateColorScale({
|
||||
* name: "blue",
|
||||
* color: {
|
||||
* hue: {
|
||||
* start: 210,
|
||||
* end: 240,
|
||||
* curve: "easeInOut"
|
||||
* },
|
||||
* saturation: {
|
||||
* start: 100,
|
||||
* end: 100,
|
||||
* curve: "easeInOut"
|
||||
* },
|
||||
* lightness: {
|
||||
* start: 50,
|
||||
* end: 50,
|
||||
* curve: "easeInOut"
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
|
||||
export function generateColorScale(
|
||||
config: ColorFamilyConfig,
|
||||
inverted: Boolean = false
|
||||
) {
|
||||
const { hue, saturation, lightness } = config.color;
|
||||
|
||||
// 101 steps means we get values from 0-100
|
||||
const NUM_STEPS = 101;
|
||||
|
||||
const hueEasing = curve(hue.curve, inverted);
|
||||
const saturationEasing = curve(saturation.curve, inverted);
|
||||
const lightnessEasing = curve(lightness.curve, inverted);
|
||||
|
||||
let scale: ColorScale = {
|
||||
colors: [],
|
||||
values: [],
|
||||
};
|
||||
|
||||
for (let i = 0; i < NUM_STEPS; i++) {
|
||||
const color = generateColor(
|
||||
hueEasing,
|
||||
saturationEasing,
|
||||
lightnessEasing,
|
||||
config,
|
||||
i,
|
||||
NUM_STEPS
|
||||
);
|
||||
|
||||
scale.colors.push(color);
|
||||
scale.values.push(color.hex);
|
||||
}
|
||||
|
||||
return scale;
|
||||
}
|
||||
|
||||
/** Generates a color family with a scale and an inverted scale. */
|
||||
export function generateColorFamily(config: ColorFamilyConfig) {
|
||||
const scale = generateColorScale(config, false);
|
||||
const invertedScale = generateColorScale(config, true);
|
||||
|
||||
const family: ColorFamily = {
|
||||
name: config.name,
|
||||
scale,
|
||||
invertedScale,
|
||||
};
|
||||
|
||||
return family;
|
||||
}
|
|
@ -1,336 +1,376 @@
|
|||
import chroma from "chroma-js";
|
||||
import {
|
||||
generateColors2,
|
||||
generateColorSet,
|
||||
generateColorsUsingCurve,
|
||||
} from "../algorithm";
|
||||
import { curve } from "../curves";
|
||||
import { ColorFamily } from "../types";
|
||||
import { generateColorFamily } from "../lib/generate";
|
||||
import { curve } from "./curves";
|
||||
|
||||
// These are the source colors for the color scales in the system.
|
||||
// This should never directly be used in the system, or exported to be used in a component or theme
|
||||
// As it will generate thousands of lines of code.
|
||||
// These should never directly be used directly in components or themes as they generate thousands of lines of code.
|
||||
// Instead, use the outputs from the reference palette which exports a smaller subset of colors.
|
||||
|
||||
// Token or user-facing colors should use short, clear names
|
||||
// and a 100-900 scale to match the font weight scale.
|
||||
// Token or user-facing colors should use short, clear names and a 100-900 scale to match the font weight scale.
|
||||
|
||||
// Red ======================================== //
|
||||
|
||||
export const red = generateColors2(
|
||||
{
|
||||
start: 0,
|
||||
end: 0,
|
||||
curve: curve.linear,
|
||||
export const red = generateColorFamily({
|
||||
name: "red",
|
||||
color: {
|
||||
hue: {
|
||||
start: 0,
|
||||
end: 0,
|
||||
curve: curve.linear,
|
||||
},
|
||||
saturation: {
|
||||
start: 95,
|
||||
end: 75,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
lightness: {
|
||||
start: 97,
|
||||
end: 25,
|
||||
curve: curve.lightness,
|
||||
},
|
||||
},
|
||||
{
|
||||
start: 95,
|
||||
end: 75,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
{
|
||||
start: 97,
|
||||
end: 25,
|
||||
curve: curve.lightness,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Sunset ======================================== //
|
||||
|
||||
export const sunset = generateColors2(
|
||||
{
|
||||
start: 12,
|
||||
end: 12,
|
||||
curve: curve.linear,
|
||||
export const sunset = generateColorFamily({
|
||||
name: "sunset",
|
||||
color: {
|
||||
hue: {
|
||||
start: 12,
|
||||
end: 12,
|
||||
curve: curve.linear,
|
||||
},
|
||||
saturation: {
|
||||
start: 100,
|
||||
end: 80,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
lightness: {
|
||||
start: 97,
|
||||
end: 25,
|
||||
curve: curve.lightness,
|
||||
},
|
||||
},
|
||||
{
|
||||
start: 100,
|
||||
end: 80,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
{
|
||||
start: 97,
|
||||
end: 25,
|
||||
curve: curve.lightness,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Orange ======================================== //
|
||||
|
||||
export const orange = generateColors2(
|
||||
{
|
||||
start: 25,
|
||||
end: 25,
|
||||
curve: curve.linear,
|
||||
export const orange = generateColorFamily({
|
||||
name: "orange",
|
||||
color: {
|
||||
hue: {
|
||||
start: 25,
|
||||
end: 25,
|
||||
curve: curve.linear,
|
||||
},
|
||||
saturation: {
|
||||
start: 100,
|
||||
end: 100,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
lightness: {
|
||||
start: 97,
|
||||
end: 25,
|
||||
curve: curve.lightness,
|
||||
},
|
||||
},
|
||||
{
|
||||
start: 100,
|
||||
end: 100,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
{
|
||||
start: 97,
|
||||
end: 25,
|
||||
curve: curve.lightness,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Amber ======================================== //
|
||||
|
||||
export const amber = generateColors2(
|
||||
{
|
||||
start: 34,
|
||||
end: 34,
|
||||
curve: curve.linear,
|
||||
export const amber = generateColorFamily({
|
||||
name: "amber",
|
||||
color: {
|
||||
hue: {
|
||||
start: 34,
|
||||
end: 34,
|
||||
curve: curve.linear,
|
||||
},
|
||||
saturation: {
|
||||
start: 100,
|
||||
end: 100,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
lightness: {
|
||||
start: 97,
|
||||
end: 25,
|
||||
curve: curve.lightness,
|
||||
},
|
||||
},
|
||||
{
|
||||
start: 100,
|
||||
end: 100,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
{
|
||||
start: 97,
|
||||
end: 25,
|
||||
curve: curve.lightness,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Yellow ======================================== //
|
||||
|
||||
export const yellow = generateColors2(
|
||||
{
|
||||
start: 48,
|
||||
end: 48,
|
||||
curve: curve.linear,
|
||||
export const yellow = generateColorFamily({
|
||||
name: "yellow",
|
||||
color: {
|
||||
hue: {
|
||||
start: 48,
|
||||
end: 48,
|
||||
curve: curve.linear,
|
||||
},
|
||||
saturation: {
|
||||
start: 90,
|
||||
end: 100,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
lightness: {
|
||||
start: 97,
|
||||
end: 28,
|
||||
curve: curve.lightness,
|
||||
},
|
||||
},
|
||||
{
|
||||
start: 90,
|
||||
end: 100,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
{
|
||||
start: 97,
|
||||
end: 32,
|
||||
curve: curve.lightness,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Citron ======================================== //
|
||||
|
||||
export const citron = generateColors2(
|
||||
{
|
||||
start: 65,
|
||||
end: 65,
|
||||
curve: curve.linear,
|
||||
export const citron = generateColorFamily({
|
||||
name: "citron",
|
||||
color: {
|
||||
hue: {
|
||||
start: 65,
|
||||
end: 65,
|
||||
curve: curve.linear,
|
||||
},
|
||||
saturation: {
|
||||
start: 85,
|
||||
end: 70,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
lightness: {
|
||||
start: 97,
|
||||
end: 25,
|
||||
curve: curve.lightness,
|
||||
},
|
||||
},
|
||||
{
|
||||
start: 85,
|
||||
end: 70,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
{
|
||||
start: 97,
|
||||
end: 25,
|
||||
curve: curve.lightness,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Lime ======================================== //
|
||||
|
||||
export const lime = generateColors2(
|
||||
{
|
||||
start: 85,
|
||||
end: 85,
|
||||
curve: curve.linear,
|
||||
export const lime = generateColorFamily({
|
||||
name: "lime",
|
||||
color: {
|
||||
hue: {
|
||||
start: 85,
|
||||
end: 85,
|
||||
curve: curve.linear,
|
||||
},
|
||||
saturation: {
|
||||
start: 85,
|
||||
end: 70,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
lightness: {
|
||||
start: 97,
|
||||
end: 25,
|
||||
curve: curve.lightness,
|
||||
},
|
||||
},
|
||||
{
|
||||
start: 85,
|
||||
end: 70,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
{
|
||||
start: 97,
|
||||
end: 25,
|
||||
curve: curve.lightness,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Green ======================================== //
|
||||
|
||||
export const green = generateColors2(
|
||||
{
|
||||
start: 108,
|
||||
end: 108,
|
||||
curve: curve.linear,
|
||||
export const green = generateColorFamily({
|
||||
name: "green",
|
||||
color: {
|
||||
hue: {
|
||||
start: 108,
|
||||
end: 108,
|
||||
curve: curve.linear,
|
||||
},
|
||||
saturation: {
|
||||
start: 60,
|
||||
end: 50,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
lightness: {
|
||||
start: 97,
|
||||
end: 25,
|
||||
curve: curve.lightness,
|
||||
},
|
||||
},
|
||||
{
|
||||
start: 60,
|
||||
end: 50,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
{
|
||||
start: 97,
|
||||
end: 25,
|
||||
curve: curve.lightness,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Mint ======================================== //
|
||||
|
||||
export const mint = generateColors2(
|
||||
{
|
||||
start: 142,
|
||||
end: 142,
|
||||
curve: curve.linear,
|
||||
export const mint = generateColorFamily({
|
||||
name: "mint",
|
||||
color: {
|
||||
hue: {
|
||||
start: 142,
|
||||
end: 142,
|
||||
curve: curve.linear,
|
||||
},
|
||||
saturation: {
|
||||
start: 60,
|
||||
end: 50,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
lightness: {
|
||||
start: 97,
|
||||
end: 20,
|
||||
curve: curve.lightness,
|
||||
},
|
||||
},
|
||||
{
|
||||
start: 60,
|
||||
end: 50,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
{
|
||||
start: 97,
|
||||
end: 20,
|
||||
curve: curve.lightness,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Cyan ======================================== //
|
||||
|
||||
export const cyan = generateColors2(
|
||||
{
|
||||
start: 179,
|
||||
end: 179,
|
||||
curve: curve.linear,
|
||||
export const cyan = generateColorFamily({
|
||||
name: "cyan",
|
||||
color: {
|
||||
hue: {
|
||||
start: 179,
|
||||
end: 179,
|
||||
curve: curve.linear,
|
||||
},
|
||||
saturation: {
|
||||
start: 70,
|
||||
end: 60,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
lightness: {
|
||||
start: 97,
|
||||
end: 20,
|
||||
curve: curve.lightness,
|
||||
},
|
||||
},
|
||||
{
|
||||
start: 70,
|
||||
end: 60,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
{
|
||||
start: 97,
|
||||
end: 20,
|
||||
curve: curve.lightness,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Sky ======================================== //
|
||||
|
||||
export const sky = generateColors2(
|
||||
{
|
||||
start: 190,
|
||||
end: 190,
|
||||
curve: curve.linear,
|
||||
export const sky = generateColorFamily({
|
||||
name: "sky",
|
||||
color: {
|
||||
hue: {
|
||||
start: 195,
|
||||
end: 195,
|
||||
curve: curve.linear,
|
||||
},
|
||||
saturation: {
|
||||
start: 85,
|
||||
end: 75,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
lightness: {
|
||||
start: 97,
|
||||
end: 20,
|
||||
curve: curve.lightness,
|
||||
},
|
||||
},
|
||||
{
|
||||
start: 85,
|
||||
end: 75,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
{
|
||||
start: 97,
|
||||
end: 20,
|
||||
curve: curve.lightness,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Blue ======================================== //
|
||||
|
||||
export const blue = generateColors2(
|
||||
{
|
||||
start: 210,
|
||||
end: 210,
|
||||
curve: curve.linear,
|
||||
export const blue = generateColorFamily({
|
||||
name: "blue",
|
||||
color: {
|
||||
hue: {
|
||||
start: 210,
|
||||
end: 210,
|
||||
curve: curve.linear,
|
||||
},
|
||||
saturation: {
|
||||
start: 90,
|
||||
end: 75,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
lightness: {
|
||||
start: 97,
|
||||
end: 20,
|
||||
curve: curve.lightness,
|
||||
},
|
||||
},
|
||||
{
|
||||
start: 90,
|
||||
end: 60,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
{
|
||||
start: 97,
|
||||
end: 20,
|
||||
curve: curve.lightness,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Indigo ======================================== //
|
||||
|
||||
export const indigo = generateColors2(
|
||||
{
|
||||
start: 240,
|
||||
end: 240,
|
||||
curve: curve.linear,
|
||||
export const indigo = generateColorFamily({
|
||||
name: "indigo",
|
||||
color: {
|
||||
hue: {
|
||||
start: 230,
|
||||
end: 230,
|
||||
curve: curve.linear,
|
||||
},
|
||||
saturation: {
|
||||
start: 80,
|
||||
end: 50,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
lightness: {
|
||||
start: 97,
|
||||
end: 20,
|
||||
curve: curve.lightness,
|
||||
},
|
||||
},
|
||||
{
|
||||
start: 80,
|
||||
end: 40,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
{
|
||||
start: 97,
|
||||
end: 20,
|
||||
curve: curve.lightness,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Purple ======================================== //
|
||||
|
||||
export const purple = generateColors2(
|
||||
{
|
||||
start: 260,
|
||||
end: 265,
|
||||
curve: curve.linear,
|
||||
export const purple = generateColorFamily({
|
||||
name: "purple",
|
||||
color: {
|
||||
hue: {
|
||||
start: 260,
|
||||
end: 265,
|
||||
curve: curve.linear,
|
||||
},
|
||||
saturation: {
|
||||
start: 80,
|
||||
end: 50,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
lightness: {
|
||||
start: 97,
|
||||
end: 20,
|
||||
curve: curve.lightness,
|
||||
},
|
||||
},
|
||||
{
|
||||
start: 80,
|
||||
end: 50,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
{
|
||||
start: 97,
|
||||
end: 20,
|
||||
curve: curve.lightness,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Pink ======================================== //
|
||||
|
||||
export const pink = generateColors2(
|
||||
{
|
||||
start: 310,
|
||||
end: 310,
|
||||
curve: curve.linear,
|
||||
export const pink = generateColorFamily({
|
||||
name: "pink",
|
||||
color: {
|
||||
hue: {
|
||||
start: 310,
|
||||
end: 310,
|
||||
curve: curve.linear,
|
||||
},
|
||||
saturation: {
|
||||
start: 80,
|
||||
end: 75,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
lightness: {
|
||||
start: 97,
|
||||
end: 20,
|
||||
curve: curve.lightness,
|
||||
},
|
||||
},
|
||||
{
|
||||
start: 80,
|
||||
end: 70,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
{
|
||||
start: 97,
|
||||
end: 20,
|
||||
curve: curve.lightness,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Rose ======================================== //
|
||||
|
||||
export const rose = generateColors2(
|
||||
{
|
||||
start: 345,
|
||||
end: 345,
|
||||
curve: curve.linear,
|
||||
export const rose = generateColorFamily({
|
||||
name: "rose",
|
||||
color: {
|
||||
hue: {
|
||||
start: 345,
|
||||
end: 345,
|
||||
curve: curve.linear,
|
||||
},
|
||||
saturation: {
|
||||
start: 90,
|
||||
end: 65,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
lightness: {
|
||||
start: 97,
|
||||
end: 20,
|
||||
curve: curve.lightness,
|
||||
},
|
||||
},
|
||||
{
|
||||
start: 90,
|
||||
end: 65,
|
||||
curve: curve.saturation,
|
||||
},
|
||||
{
|
||||
start: 97,
|
||||
end: 20,
|
||||
curve: curve.lightness,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
25
styles/src/system/ref/curves.ts
Normal file
25
styles/src/system/ref/curves.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
export interface Curve {
|
||||
name: string;
|
||||
value: number[];
|
||||
}
|
||||
|
||||
export interface Curves {
|
||||
lightness: Curve;
|
||||
saturation: Curve;
|
||||
linear: Curve;
|
||||
}
|
||||
|
||||
export const curve: Curves = {
|
||||
lightness: {
|
||||
name: "lightnessCurve",
|
||||
value: [0.2, 0, 0.85, 1.0],
|
||||
},
|
||||
saturation: {
|
||||
name: "saturationCurve",
|
||||
value: [0.67, 0.6, 0.55, 1.0],
|
||||
},
|
||||
linear: {
|
||||
name: "linear",
|
||||
value: [0.5, 0.5, 0.5, 0.5],
|
||||
},
|
||||
};
|
|
@ -1,3 +0,0 @@
|
|||
import * as color from "./ref/color";
|
||||
|
||||
export { color };
|
23
styles/src/system/system.ts
Normal file
23
styles/src/system/system.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import chroma from "chroma-js";
|
||||
import * as colorFamily from "./ref/color";
|
||||
|
||||
const color = {
|
||||
red: chroma.scale(colorFamily.red.scale.values).mode("lch").colors(9),
|
||||
sunset: chroma.scale(colorFamily.sunset.scale.values).mode("lch").colors(9),
|
||||
orange: chroma.scale(colorFamily.orange.scale.values).mode("lch").colors(9),
|
||||
amber: chroma.scale(colorFamily.amber.scale.values).mode("lch").colors(9),
|
||||
yellow: chroma.scale(colorFamily.yellow.scale.values).mode("lch").colors(9),
|
||||
citron: chroma.scale(colorFamily.citron.scale.values).mode("lch").colors(9),
|
||||
lime: chroma.scale(colorFamily.lime.scale.values).mode("lch").colors(9),
|
||||
green: chroma.scale(colorFamily.green.scale.values).mode("lch").colors(9),
|
||||
mint: chroma.scale(colorFamily.mint.scale.values).mode("lch").colors(9),
|
||||
cyan: chroma.scale(colorFamily.cyan.scale.values).mode("lch").colors(9),
|
||||
sky: chroma.scale(colorFamily.sky.scale.values).mode("lch").colors(9),
|
||||
blue: chroma.scale(colorFamily.blue.scale.values).mode("lch").colors(9),
|
||||
indigo: chroma.scale(colorFamily.indigo.scale.values).mode("lch").colors(9),
|
||||
purple: chroma.scale(colorFamily.purple.scale.values).mode("lch").colors(9),
|
||||
pink: chroma.scale(colorFamily.pink.scale.values).mode("lch").colors(9),
|
||||
rose: chroma.scale(colorFamily.rose.scale.values).mode("lch").colors(9),
|
||||
};
|
||||
|
||||
export { color };
|
|
@ -1,27 +1,67 @@
|
|||
import { Color as ChromaColor } from "chroma-js";
|
||||
import { Curve } from "./ref/curves";
|
||||
|
||||
export interface ColorAccessiblityValue {
|
||||
value: number;
|
||||
aaPass: boolean;
|
||||
aaaPass: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the color contrast between a specified color and its corresponding background and foreground colors.
|
||||
*
|
||||
* @note This implementation is currently basic – Currently we only calculate contrasts against black and white, in the future will allow for dynamic color contrast calculation based on the colors present in a given palette.
|
||||
* @note The goal is to align with WCAG3 accessibility standards as they become stabilized. See the [WCAG 3 Introduction](https://www.w3.org/WAI/standards-guidelines/wcag/wcag3-intro/) for more information.
|
||||
*/
|
||||
export interface ColorAccessiblity {
|
||||
black: ColorAccessiblityValue;
|
||||
white: ColorAccessiblityValue;
|
||||
}
|
||||
|
||||
export type Color = {
|
||||
step: number;
|
||||
contrast: ColorAccessiblity;
|
||||
hex: string;
|
||||
lch: number[];
|
||||
rgbaArray: number[];
|
||||
rgba: number[];
|
||||
isLight: boolean;
|
||||
};
|
||||
|
||||
export type ColorSet = Color[];
|
||||
export interface ColorScale {
|
||||
colors: Color[];
|
||||
// An array of hex values for each color in the scale
|
||||
values: string[];
|
||||
}
|
||||
|
||||
export type ColorFamily = {
|
||||
name: string;
|
||||
colors: string[];
|
||||
invertedColors: string[];
|
||||
colorsMeta: ColorSet;
|
||||
invertedMeta: ColorSet;
|
||||
scale: ColorScale;
|
||||
invertedScale: ColorScale;
|
||||
};
|
||||
|
||||
export interface ColorProps {
|
||||
export interface ColorFamilyHue {
|
||||
start: number;
|
||||
end: number;
|
||||
curve: Curve;
|
||||
}
|
||||
|
||||
export interface ColorFamilySaturation {
|
||||
start: number;
|
||||
end: number;
|
||||
curve: Curve;
|
||||
}
|
||||
|
||||
export interface ColorFamilyLightness {
|
||||
start: number;
|
||||
end: number;
|
||||
curve: Curve;
|
||||
}
|
||||
|
||||
export interface ColorFamilyConfig {
|
||||
name: string;
|
||||
color: {
|
||||
start: string | ChromaColor;
|
||||
middle: string | ChromaColor;
|
||||
end: string | ChromaColor;
|
||||
hue: ColorFamilyHue;
|
||||
saturation: ColorFamilySaturation;
|
||||
lightness: ColorFamilyLightness;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
/* eslint-disable import/no-relative-packages */
|
||||
import { Scale } from 'chroma-js';
|
||||
|
||||
import { color } from '../../src/system/reference';
|
||||
import { color } from '../../src/system/system';
|
||||
import styles from './page.module.css';
|
||||
|
||||
function ColorChips({ colorScale }: { colorScale: Scale }) {
|
||||
const colors = colorScale.colors(11);
|
||||
|
||||
function ColorChips({ colors }: { colors: string[] }) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
|
@ -38,22 +34,22 @@ export default function Home() {
|
|||
return (
|
||||
<main>
|
||||
<div style={{ display: 'flex', gap: '1px' }}>
|
||||
<ColorChips colorScale={color.red} />
|
||||
<ColorChips colorScale={color.sunset} />
|
||||
<ColorChips colorScale={color.orange} />
|
||||
<ColorChips colorScale={color.amber} />
|
||||
<ColorChips colorScale={color.yellow} />
|
||||
<ColorChips colorScale={color.citron} />
|
||||
<ColorChips colorScale={color.lime} />
|
||||
<ColorChips colorScale={color.green} />
|
||||
<ColorChips colorScale={color.mint} />
|
||||
<ColorChips colorScale={color.cyan} />
|
||||
<ColorChips colorScale={color.sky} />
|
||||
<ColorChips colorScale={color.blue} />
|
||||
<ColorChips colorScale={color.indigo} />
|
||||
<ColorChips colorScale={color.purple} />
|
||||
<ColorChips colorScale={color.pink} />
|
||||
<ColorChips colorScale={color.rose} />
|
||||
<ColorChips colors={color.red} />
|
||||
<ColorChips colors={color.sunset} />
|
||||
<ColorChips colors={color.orange} />
|
||||
<ColorChips colors={color.amber} />
|
||||
<ColorChips colors={color.yellow} />
|
||||
<ColorChips colors={color.citron} />
|
||||
<ColorChips colors={color.lime} />
|
||||
<ColorChips colors={color.green} />
|
||||
<ColorChips colors={color.mint} />
|
||||
<ColorChips colors={color.cyan} />
|
||||
<ColorChips colors={color.sky} />
|
||||
<ColorChips colors={color.blue} />
|
||||
<ColorChips colors={color.indigo} />
|
||||
<ColorChips colors={color.purple} />
|
||||
<ColorChips colors={color.pink} />
|
||||
<ColorChips colors={color.rose} />
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue