@@ -1,6 +1,12 @@
-import { Scale } from "chroma-js"
+import { Scale, Color } from "chroma-js"
import { Syntax, ThemeSyntax, SyntaxHighlightStyle } from "./syntax"
export { Syntax, ThemeSyntax, SyntaxHighlightStyle }
+import {
+ ThemeConfig,
+ ThemeAppearance,
+ ThemeConfigInputColors,
+} from "../../themeConfig"
+import { getRamps } from "./ramps"
export interface ColorScheme {
name: string
@@ -103,3 +109,183 @@ export interface Style {
border: string
foreground: string
}
+
+export function createColorScheme(theme: ThemeConfig): ColorScheme {
+ const {
+ name,
+ appearance,
+ inputColor,
+ override: { syntax },
+ } = theme
+
+ const isLight = appearance === ThemeAppearance.Light
+ const colorRamps: ThemeConfigInputColors = inputColor
+
+ // Chromajs scales from 0 to 1 flipped if isLight is true
+ const ramps = getRamps(isLight, colorRamps)
+ const lowest = lowestLayer(ramps)
+ const middle = middleLayer(ramps)
+ const highest = highestLayer(ramps)
+
+ const popoverShadow = {
+ blur: 4,
+ color: ramps
+ .neutral(isLight ? 7 : 0)
+ .darken()
+ .alpha(0.2)
+ .hex(), // TODO used blend previously. Replace with something else
+ offset: [1, 2],
+ }
+
+ const modalShadow = {
+ blur: 16,
+ color: ramps
+ .neutral(isLight ? 7 : 0)
+ .darken()
+ .alpha(0.2)
+ .hex(), // TODO used blend previously. Replace with something else
+ offset: [0, 2],
+ }
+
+ const players = {
+ "0": player(ramps.blue),
+ "1": player(ramps.green),
+ "2": player(ramps.magenta),
+ "3": player(ramps.orange),
+ "4": player(ramps.violet),
+ "5": player(ramps.cyan),
+ "6": player(ramps.red),
+ "7": player(ramps.yellow),
+ }
+
+ return {
+ name,
+ isLight,
+
+ ramps,
+
+ lowest,
+ middle,
+ highest,
+
+ popoverShadow,
+ modalShadow,
+
+ players,
+ syntax,
+ }
+}
+
+function player(ramp: Scale): Player {
+ return {
+ selection: ramp(0.5).alpha(0.24).hex(),
+ cursor: ramp(0.5).hex(),
+ }
+}
+
+function lowestLayer(ramps: RampSet): Layer {
+ return {
+ base: buildStyleSet(ramps.neutral, 0.2, 1),
+ variant: buildStyleSet(ramps.neutral, 0.2, 0.7),
+ on: buildStyleSet(ramps.neutral, 0.1, 1),
+ accent: buildStyleSet(ramps.blue, 0.1, 0.5),
+ positive: buildStyleSet(ramps.green, 0.1, 0.5),
+ warning: buildStyleSet(ramps.yellow, 0.1, 0.5),
+ negative: buildStyleSet(ramps.red, 0.1, 0.5),
+ }
+}
+
+function middleLayer(ramps: RampSet): Layer {
+ return {
+ base: buildStyleSet(ramps.neutral, 0.1, 1),
+ variant: buildStyleSet(ramps.neutral, 0.1, 0.7),
+ on: buildStyleSet(ramps.neutral, 0, 1),
+ accent: buildStyleSet(ramps.blue, 0.1, 0.5),
+ positive: buildStyleSet(ramps.green, 0.1, 0.5),
+ warning: buildStyleSet(ramps.yellow, 0.1, 0.5),
+ negative: buildStyleSet(ramps.red, 0.1, 0.5),
+ }
+}
+
+function highestLayer(ramps: RampSet): Layer {
+ return {
+ base: buildStyleSet(ramps.neutral, 0, 1),
+ variant: buildStyleSet(ramps.neutral, 0, 0.7),
+ on: buildStyleSet(ramps.neutral, 0.1, 1),
+ accent: buildStyleSet(ramps.blue, 0.1, 0.5),
+ positive: buildStyleSet(ramps.green, 0.1, 0.5),
+ warning: buildStyleSet(ramps.yellow, 0.1, 0.5),
+ negative: buildStyleSet(ramps.red, 0.1, 0.5),
+ }
+}
+
+function buildStyleSet(
+ ramp: Scale,
+ backgroundBase: number,
+ foregroundBase: number,
+ step: number = 0.08
+): StyleSet {
+ let styleDefinitions = buildStyleDefinition(
+ backgroundBase,
+ foregroundBase,
+ step
+ )
+
+ function colorString(indexOrColor: number | Color): string {
+ if (typeof indexOrColor === "number") {
+ return ramp(indexOrColor).hex()
+ } else {
+ return indexOrColor.hex()
+ }
+ }
+
+ function buildStyle(style: Styles): Style {
+ return {
+ background: colorString(styleDefinitions.background[style]),
+ border: colorString(styleDefinitions.border[style]),
+ foreground: colorString(styleDefinitions.foreground[style]),
+ }
+ }
+
+ return {
+ default: buildStyle("default"),
+ hovered: buildStyle("hovered"),
+ pressed: buildStyle("pressed"),
+ active: buildStyle("active"),
+ disabled: buildStyle("disabled"),
+ inverted: buildStyle("inverted"),
+ }
+}
+
+function buildStyleDefinition(
+ bgBase: number,
+ fgBase: number,
+ step: number = 0.08
+) {
+ return {
+ background: {
+ default: bgBase,
+ hovered: bgBase + step,
+ pressed: bgBase + step * 1.5,
+ active: bgBase + step * 2.2,
+ disabled: bgBase,
+ inverted: fgBase + step * 6,
+ },
+ border: {
+ default: bgBase + step * 1,
+ hovered: bgBase + step,
+ pressed: bgBase + step,
+ active: bgBase + step * 3,
+ disabled: bgBase + step * 0.5,
+ inverted: bgBase - step * 3,
+ },
+ foreground: {
+ default: fgBase,
+ hovered: fgBase,
+ pressed: fgBase,
+ active: fgBase + step * 6,
+ disabled: bgBase + step * 4,
+ inverted: bgBase + step * 2,
+ },
+ }
+}
@@ -1,14 +1,9 @@
import chroma, { Color, Scale } from "chroma-js"
+import { RampSet } from "./colorScheme"
import {
- ColorScheme,
- Layer,
- Player,
- RampSet,
- Style,
- Styles,
- StyleSet,
- ThemeSyntax,
-} from "./colorScheme"
+ ThemeConfigInputColors,
+ ThemeConfigInputColorsKeys,
+} from "../../themeConfig"
export function colorRamp(color: Color): Scale {
let endColor = color.desaturate(1).brighten(5)
@@ -16,200 +11,37 @@ export function colorRamp(color: Color): Scale {
return chroma.scale([startColor, color, endColor]).mode("lab")
}
-export function createColorScheme(
- name: string,
+/**
+ * Chromajs mutates the underlying ramp when you call domain. This causes problems because
+ we now store the ramps object in the theme so that we can pull colors out of them.
+ So instead of calling domain and storing the result, we have to construct new ramps for each
+ theme so that we don't modify the passed in ramps.
+ This combined with an error in the type definitions for chroma js means we have to cast the colors
+ function to any in order to get the colors back out from the original ramps.
+ * @param isLight
+ * @param colorRamps
+ * @returns
+ */
+export function getRamps(
isLight: boolean,
- colorRamps: { [rampName: string]: Scale },
- syntax?: ThemeSyntax
-): ColorScheme {
- // Chromajs scales from 0 to 1 flipped if isLight is true
- let ramps: RampSet = {} as any
+ colorRamps: ThemeConfigInputColors
+): RampSet {
+ const ramps: RampSet = {} as any
+ const colorsKeys = Object.keys(colorRamps) as ThemeConfigInputColorsKeys[]
- // Chromajs mutates the underlying ramp when you call domain. This causes problems because
- // we now store the ramps object in the theme so that we can pull colors out of them.
- // So instead of calling domain and storing the result, we have to construct new ramps for each
- // theme so that we don't modify the passed in ramps.
- // This combined with an error in the type definitions for chroma js means we have to cast the colors
- // function to any in order to get the colors back out from the original ramps.
if (isLight) {
- for (var rampName in colorRamps) {
- ;(ramps as any)[rampName] = chroma.scale(
+ for (const rampName of colorsKeys) {
+ ramps[rampName] = chroma.scale(
colorRamps[rampName].colors(100).reverse()
)
}
ramps.neutral = chroma.scale(colorRamps.neutral.colors(100).reverse())
} else {
- for (var rampName in colorRamps) {
- ;(ramps as any)[rampName] = chroma.scale(
- colorRamps[rampName].colors(100)
- )
+ for (const rampName of colorsKeys) {
+ ramps[rampName] = chroma.scale(colorRamps[rampName].colors(100))
}
ramps.neutral = chroma.scale(colorRamps.neutral.colors(100))
}
- let lowest = lowestLayer(ramps)
- let middle = middleLayer(ramps)
- let highest = highestLayer(ramps)
-
- let popoverShadow = {
- blur: 4,
- color: ramps
- .neutral(isLight ? 7 : 0)
- .darken()
- .alpha(0.2)
- .hex(), // TODO used blend previously. Replace with something else
- offset: [1, 2],
- }
-
- let modalShadow = {
- blur: 16,
- color: ramps
- .neutral(isLight ? 7 : 0)
- .darken()
- .alpha(0.2)
- .hex(), // TODO used blend previously. Replace with something else
- offset: [0, 2],
- }
-
- let players = {
- "0": player(ramps.blue),
- "1": player(ramps.green),
- "2": player(ramps.magenta),
- "3": player(ramps.orange),
- "4": player(ramps.violet),
- "5": player(ramps.cyan),
- "6": player(ramps.red),
- "7": player(ramps.yellow),
- }
-
- return {
- name,
- isLight,
-
- ramps,
-
- lowest,
- middle,
- highest,
-
- popoverShadow,
- modalShadow,
-
- players,
- syntax,
- }
-}
-
-function player(ramp: Scale): Player {
- return {
- selection: ramp(0.5).alpha(0.24).hex(),
- cursor: ramp(0.5).hex(),
- }
-}
-
-function lowestLayer(ramps: RampSet): Layer {
- return {
- base: buildStyleSet(ramps.neutral, 0.2, 1),
- variant: buildStyleSet(ramps.neutral, 0.2, 0.7),
- on: buildStyleSet(ramps.neutral, 0.1, 1),
- accent: buildStyleSet(ramps.blue, 0.1, 0.5),
- positive: buildStyleSet(ramps.green, 0.1, 0.5),
- warning: buildStyleSet(ramps.yellow, 0.1, 0.5),
- negative: buildStyleSet(ramps.red, 0.1, 0.5),
- }
-}
-
-function middleLayer(ramps: RampSet): Layer {
- return {
- base: buildStyleSet(ramps.neutral, 0.1, 1),
- variant: buildStyleSet(ramps.neutral, 0.1, 0.7),
- on: buildStyleSet(ramps.neutral, 0, 1),
- accent: buildStyleSet(ramps.blue, 0.1, 0.5),
- positive: buildStyleSet(ramps.green, 0.1, 0.5),
- warning: buildStyleSet(ramps.yellow, 0.1, 0.5),
- negative: buildStyleSet(ramps.red, 0.1, 0.5),
- }
-}
-
-function highestLayer(ramps: RampSet): Layer {
- return {
- base: buildStyleSet(ramps.neutral, 0, 1),
- variant: buildStyleSet(ramps.neutral, 0, 0.7),
- on: buildStyleSet(ramps.neutral, 0.1, 1),
- accent: buildStyleSet(ramps.blue, 0.1, 0.5),
- positive: buildStyleSet(ramps.green, 0.1, 0.5),
- warning: buildStyleSet(ramps.yellow, 0.1, 0.5),
- negative: buildStyleSet(ramps.red, 0.1, 0.5),
- }
-}
-
-function buildStyleSet(
- ramp: Scale,
- backgroundBase: number,
- foregroundBase: number,
- step: number = 0.08
-): StyleSet {
- let styleDefinitions = buildStyleDefinition(
- backgroundBase,
- foregroundBase,
- step
- )
-
- function colorString(indexOrColor: number | Color): string {
- if (typeof indexOrColor === "number") {
- return ramp(indexOrColor).hex()
- } else {
- return indexOrColor.hex()
- }
- }
-
- function buildStyle(style: Styles): Style {
- return {
- background: colorString(styleDefinitions.background[style]),
- border: colorString(styleDefinitions.border[style]),
- foreground: colorString(styleDefinitions.foreground[style]),
- }
- }
-
- return {
- default: buildStyle("default"),
- hovered: buildStyle("hovered"),
- pressed: buildStyle("pressed"),
- active: buildStyle("active"),
- disabled: buildStyle("disabled"),
- inverted: buildStyle("inverted"),
- }
-}
-
-function buildStyleDefinition(
- bgBase: number,
- fgBase: number,
- step: number = 0.08
-) {
- return {
- background: {
- default: bgBase,
- hovered: bgBase + step,
- pressed: bgBase + step * 1.5,
- active: bgBase + step * 2.2,
- disabled: bgBase,
- inverted: fgBase + step * 6,
- },
- border: {
- default: bgBase + step * 1,
- hovered: bgBase + step,
- pressed: bgBase + step,
- active: bgBase + step * 3,
- disabled: bgBase + step * 0.5,
- inverted: bgBase - step * 3,
- },
- foreground: {
- default: fgBase,
- hovered: fgBase,
- pressed: fgBase,
- active: fgBase + step * 6,
- disabled: bgBase + step * 4,
- inverted: bgBase + step * 2,
- },
- }
+ return ramps
}