mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-26 10:40:54 +00:00
feat: update and refactor colorScheme
This commit is contained in:
parent
56ecfaf2f0
commit
6b00db75ad
2 changed files with 212 additions and 194 deletions
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue