`color_scheme` -> `theme`

Nate Butler created

Change summary

docs/zed/syntax-highlighting.md     |  2 
styles/src/build_themes.ts          | 16 ++--
styles/src/build_tokens.ts          | 17 +++--
styles/src/component/icon_button.ts | 14 ++--
styles/src/component/text_button.ts | 14 ++--
styles/src/style_tree/components.ts |  2 
styles/src/style_tree/editor.ts     |  4 
styles/src/theme/create_theme.ts    |  4 
styles/src/theme/index.ts           | 10 +-
styles/src/theme/ramps.ts           |  2 
styles/src/theme/syntax.ts          | 86 ++++++++++++++----------------
styles/src/theme/theme_config.ts    | 67 ------------------------
styles/src/theme/tokens/layer.ts    |  2 
styles/src/theme/tokens/players.ts  |  4 
styles/src/theme/tokens/theme.ts    | 11 +--
15 files changed, 93 insertions(+), 162 deletions(-)

Detailed changes

docs/zed/syntax-highlighting.md 🔗

@@ -35,7 +35,7 @@ Match a property identifier and highlight it using the identifier `@property`. I
 ```
 
 ```ts
-function buildDefaultSyntax(colorScheme: ColorScheme): Partial<Syntax> {
+function buildDefaultSyntax(colorScheme: Theme): Partial<Syntax> {
     // ...
 }
 ```

styles/src/build_themes.ts 🔗

@@ -2,7 +2,7 @@ import * as fs from "fs"
 import { tmpdir } from "os"
 import * as path from "path"
 import app from "./style_tree/app"
-import { ColorScheme, create_color_scheme } from "./theme/color_scheme"
+import { Theme, create_theme } from "./theme/create_theme"
 import { themes } from "./themes"
 import { useThemeStore } from "./theme"
 
@@ -21,22 +21,22 @@ function clear_themes(theme_directory: string) {
     }
 }
 
-const all_themes: ColorScheme[] = themes.map((theme) =>
-    create_color_scheme(theme)
+const all_themes: Theme[] = themes.map((theme) =>
+    create_theme(theme)
 )
 
-function write_themes(themes: ColorScheme[], output_directory: string) {
+function write_themes(themes: Theme[], output_directory: string) {
     clear_themes(output_directory)
-    for (const color_scheme of themes) {
+    for (const theme of themes) {
         const { setTheme } = useThemeStore.getState()
-        setTheme(color_scheme)
+        setTheme(theme)
 
         const style_tree = app()
         const style_tree_json = JSON.stringify(style_tree, null, 2)
-        const temp_path = path.join(temp_directory, `${color_scheme.name}.json`)
+        const temp_path = path.join(temp_directory, `${theme.name}.json`)
         const out_path = path.join(
             output_directory,
-            `${color_scheme.name}.json`
+            `${theme.name}.json`
         )
         fs.writeFileSync(temp_path, style_tree_json)
         fs.renameSync(temp_path, out_path)

styles/src/build_tokens.ts 🔗

@@ -1,9 +1,9 @@
 import * as fs from "fs"
 import * as path from "path"
-import { ColorScheme, create_color_scheme } from "./common"
+import { Theme, create_theme, useThemeStore } from "./common"
 import { themes } from "./themes"
 import { slugify } from "./utils/slugify"
-import { theme_tokens } from "./theme/tokens/color_scheme"
+import { theme_tokens } from "./theme/tokens/theme"
 
 const TOKENS_DIRECTORY = path.join(__dirname, "..", "target", "tokens")
 const TOKENS_FILE = path.join(TOKENS_DIRECTORY, "$themes.json")
@@ -27,7 +27,7 @@ type TokenSet = {
     selected_token_sets: { [key: string]: "enabled" }
 }
 
-function build_token_set_order(theme: ColorScheme[]): {
+function build_token_set_order(theme: Theme[]): {
     token_set_order: string[]
 } {
     const token_set_order: string[] = theme.map((scheme) =>
@@ -36,7 +36,7 @@ function build_token_set_order(theme: ColorScheme[]): {
     return { token_set_order }
 }
 
-function build_themes_index(theme: ColorScheme[]): TokenSet[] {
+function build_themes_index(theme: Theme[]): TokenSet[] {
     const themes_index: TokenSet[] = theme.map((scheme, index) => {
         const id = `${scheme.is_light ? "light" : "dark"}_${scheme.name
             .toLowerCase()
@@ -55,10 +55,13 @@ function build_themes_index(theme: ColorScheme[]): TokenSet[] {
     return themes_index
 }
 
-function write_tokens(themes: ColorScheme[], tokens_directory: string) {
+function write_tokens(themes: Theme[], tokens_directory: string) {
     clear_tokens(tokens_directory)
 
     for (const theme of themes) {
+        const { setTheme } = useThemeStore.getState()
+        setTheme(theme)
+
         const file_name = slugify(theme.name) + ".json"
         const tokens = theme_tokens()
         const tokens_json = JSON.stringify(tokens, null, 2)
@@ -80,8 +83,8 @@ function write_tokens(themes: ColorScheme[], tokens_directory: string) {
     console.log(`- ${METADATA_FILE} created`)
 }
 
-const all_themes: ColorScheme[] = themes.map((theme) =>
-    create_color_scheme(theme)
+const all_themes: Theme[] = themes.map((theme) =>
+    create_theme(theme)
 )
 
 write_tokens(all_themes, TOKENS_DIRECTORY)

styles/src/component/icon_button.ts 🔗

@@ -1,6 +1,6 @@
 import { interactive, toggleable } from "../element"
 import { background, foreground } from "../style_tree/components"
-import { useTheme, ColorScheme } from "../theme"
+import { useTheme, Theme } from "../theme"
 
 export type Margin = {
     top: number
@@ -11,15 +11,15 @@ export type Margin = {
 
 interface IconButtonOptions {
     layer?:
-        | ColorScheme["lowest"]
-        | ColorScheme["middle"]
-        | ColorScheme["highest"]
-    color?: keyof ColorScheme["lowest"]
+    | Theme["lowest"]
+    | Theme["middle"]
+    | Theme["highest"]
+    color?: keyof Theme["lowest"]
     margin?: Partial<Margin>
 }
 
 type ToggleableIconButtonOptions = IconButtonOptions & {
-    active_color?: keyof ColorScheme["lowest"]
+    active_color?: keyof Theme["lowest"]
 }
 
 export function icon_button({ color, margin, layer }: IconButtonOptions) {
@@ -67,7 +67,7 @@ export function icon_button({ color, margin, layer }: IconButtonOptions) {
 }
 
 export function toggleable_icon_button(
-    theme: ColorScheme,
+    theme: Theme,
     { color, active_color, margin }: ToggleableIconButtonOptions
 ) {
     if (!color) color = "base"

styles/src/component/text_button.ts 🔗

@@ -5,21 +5,21 @@ import {
     foreground,
     text,
 } from "../style_tree/components"
-import { useTheme, ColorScheme } from "../theme"
+import { useTheme, Theme } from "../theme"
 import { Margin } from "./icon_button"
 
 interface TextButtonOptions {
     layer?:
-        | ColorScheme["lowest"]
-        | ColorScheme["middle"]
-        | ColorScheme["highest"]
-    color?: keyof ColorScheme["lowest"]
+    | Theme["lowest"]
+    | Theme["middle"]
+    | Theme["highest"]
+    color?: keyof Theme["lowest"]
     margin?: Partial<Margin>
     text_properties?: TextProperties
 }
 
 type ToggleableTextButtonOptions = TextButtonOptions & {
-    active_color?: keyof ColorScheme["lowest"]
+    active_color?: keyof Theme["lowest"]
 }
 
 export function text_button({
@@ -75,7 +75,7 @@ export function text_button({
 }
 
 export function toggleable_text_button(
-    theme: ColorScheme,
+    theme: Theme,
     { color, active_color, margin }: ToggleableTextButtonOptions
 ) {
     if (!color) color = "base"

styles/src/style_tree/components.ts 🔗

@@ -1,5 +1,5 @@
 import { font_families, font_sizes, FontWeight } from "../common"
-import { Layer, Styles, StyleSets, Style } from "../theme/color_scheme"
+import { Layer, Styles, StyleSets, Style } from "../theme/create_theme"
 
 function is_style_set(key: any): key is StyleSets {
     return [

styles/src/style_tree/editor.ts 🔗

@@ -1,5 +1,5 @@
 import { with_opacity } from "../theme/color"
-import { Layer, StyleSets } from "../theme/color_scheme"
+import { Layer, StyleSets } from "../theme/create_theme"
 import {
     background,
     border,
@@ -48,7 +48,7 @@ export default function editor(): any {
         }
     }
 
-    const syntax = build_syntax(theme)
+    const syntax = build_syntax()
 
     return {
         text_color: syntax.primary.color,

styles/src/theme/color_scheme.ts → styles/src/theme/create_theme.ts 🔗

@@ -8,7 +8,7 @@ import {
 } from "./theme_config"
 import { get_ramps } from "./ramps"
 
-export interface ColorScheme {
+export interface Theme {
     name: string
     is_light: boolean
 
@@ -105,7 +105,7 @@ export interface Style {
     foreground: string
 }
 
-export function create_color_scheme(theme: ThemeConfig): ColorScheme {
+export function create_theme(theme: ThemeConfig): Theme {
     const {
         name,
         appearance,

styles/src/theme/index.ts 🔗

@@ -1,9 +1,9 @@
 import { create } from "zustand"
-import { ColorScheme } from "./color_scheme"
+import { Theme } from "./create_theme"
 
 type ThemeState = {
-    theme: ColorScheme | undefined
-    setTheme: (theme: ColorScheme) => void
+    theme: Theme | undefined
+    setTheme: (theme: Theme) => void
 }
 
 export const useThemeStore = create<ThemeState>((set) => ({
@@ -11,7 +11,7 @@ export const useThemeStore = create<ThemeState>((set) => ({
     setTheme: (theme) => set(() => ({ theme })),
 }))
 
-export const useTheme = (): ColorScheme => {
+export const useTheme = (): Theme => {
     const { theme } = useThemeStore.getState()
 
     if (!theme) throw new Error("Tried to use theme before it was loaded")
@@ -19,7 +19,7 @@ export const useTheme = (): ColorScheme => {
     return theme
 }
 
-export * from "./color_scheme"
+export * from "./create_theme"
 export * from "./ramps"
 export * from "./syntax"
 export * from "./theme_config"

styles/src/theme/ramps.ts 🔗

@@ -1,5 +1,5 @@
 import chroma, { Color, Scale } from "chroma-js"
-import { RampSet } from "./color_scheme"
+import { RampSet } from "./create_theme"
 import {
     ThemeConfigInputColors,
     ThemeConfigInputColorsKeys,

styles/src/theme/syntax.ts 🔗

@@ -1,6 +1,5 @@
 import deepmerge from "deepmerge"
-import { FontWeight, font_weights } from "../common"
-import { ColorScheme } from "./color_scheme"
+import { FontWeight, font_weights, useTheme } from "../common"
 import chroma from "chroma-js"
 
 export interface SyntaxHighlightStyle {
@@ -123,7 +122,9 @@ const default_syntax_highlight_style: Omit<SyntaxHighlightStyle, "color"> = {
     italic: false,
 }
 
-function build_default_syntax(color_scheme: ColorScheme): Syntax {
+function build_default_syntax(): Syntax {
+    const theme = useTheme()
+
     // Make a temporary object that is allowed to be missing
     // the "color" property for each style
     const syntax: {
@@ -141,8 +142,8 @@ function build_default_syntax(color_scheme: ColorScheme): Syntax {
     // predictive color distinct from any other color in the theme
     const predictive = chroma
         .mix(
-            color_scheme.ramps.neutral(0.4).hex(),
-            color_scheme.ramps.blue(0.4).hex(),
+            theme.ramps.neutral(0.4).hex(),
+            theme.ramps.blue(0.4).hex(),
             0.45,
             "lch"
         )
@@ -151,32 +152,32 @@ function build_default_syntax(color_scheme: ColorScheme): Syntax {
     // hint color distinct from any other color in the theme
     const hint = chroma
         .mix(
-            color_scheme.ramps.neutral(0.6).hex(),
-            color_scheme.ramps.blue(0.4).hex(),
+            theme.ramps.neutral(0.6).hex(),
+            theme.ramps.blue(0.4).hex(),
             0.45,
             "lch"
         )
         .hex()
 
     const color = {
-        primary: color_scheme.ramps.neutral(1).hex(),
-        comment: color_scheme.ramps.neutral(0.71).hex(),
-        punctuation: color_scheme.ramps.neutral(0.86).hex(),
+        primary: theme.ramps.neutral(1).hex(),
+        comment: theme.ramps.neutral(0.71).hex(),
+        punctuation: theme.ramps.neutral(0.86).hex(),
         predictive: predictive,
         hint: hint,
-        emphasis: color_scheme.ramps.blue(0.5).hex(),
-        string: color_scheme.ramps.orange(0.5).hex(),
-        function: color_scheme.ramps.yellow(0.5).hex(),
-        type: color_scheme.ramps.cyan(0.5).hex(),
-        constructor: color_scheme.ramps.blue(0.5).hex(),
-        variant: color_scheme.ramps.blue(0.5).hex(),
-        property: color_scheme.ramps.blue(0.5).hex(),
-        enum: color_scheme.ramps.orange(0.5).hex(),
-        operator: color_scheme.ramps.orange(0.5).hex(),
-        number: color_scheme.ramps.green(0.5).hex(),
-        boolean: color_scheme.ramps.green(0.5).hex(),
-        constant: color_scheme.ramps.green(0.5).hex(),
-        keyword: color_scheme.ramps.blue(0.5).hex(),
+        emphasis: theme.ramps.blue(0.5).hex(),
+        string: theme.ramps.orange(0.5).hex(),
+        function: theme.ramps.yellow(0.5).hex(),
+        type: theme.ramps.cyan(0.5).hex(),
+        constructor: theme.ramps.blue(0.5).hex(),
+        variant: theme.ramps.blue(0.5).hex(),
+        property: theme.ramps.blue(0.5).hex(),
+        enum: theme.ramps.orange(0.5).hex(),
+        operator: theme.ramps.orange(0.5).hex(),
+        number: theme.ramps.green(0.5).hex(),
+        boolean: theme.ramps.green(0.5).hex(),
+        constant: theme.ramps.green(0.5).hex(),
+        keyword: theme.ramps.blue(0.5).hex(),
     }
 
     // Then assign colors and use Syntax to enforce each style getting it's own color
@@ -211,11 +212,11 @@ function build_default_syntax(color_scheme: ColorScheme): Syntax {
             weight: font_weights.bold,
         },
         link_uri: {
-            color: color_scheme.ramps.green(0.5).hex(),
+            color: theme.ramps.green(0.5).hex(),
             underline: true,
         },
         link_text: {
-            color: color_scheme.ramps.orange(0.5).hex(),
+            color: theme.ramps.orange(0.5).hex(),
             italic: true,
         },
         "text.literal": {
@@ -231,7 +232,7 @@ function build_default_syntax(color_scheme: ColorScheme): Syntax {
             color: color.punctuation,
         },
         "punctuation.special": {
-            color: color_scheme.ramps.neutral(0.86).hex(),
+            color: theme.ramps.neutral(0.86).hex(),
         },
         "punctuation.list_marker": {
             color: color.punctuation,
@@ -252,10 +253,10 @@ function build_default_syntax(color_scheme: ColorScheme): Syntax {
             color: color.string,
         },
         constructor: {
-            color: color_scheme.ramps.blue(0.5).hex(),
+            color: theme.ramps.blue(0.5).hex(),
         },
         variant: {
-            color: color_scheme.ramps.blue(0.5).hex(),
+            color: theme.ramps.blue(0.5).hex(),
         },
         type: {
             color: color.type,
@@ -264,16 +265,16 @@ function build_default_syntax(color_scheme: ColorScheme): Syntax {
             color: color.primary,
         },
         label: {
-            color: color_scheme.ramps.blue(0.5).hex(),
+            color: theme.ramps.blue(0.5).hex(),
         },
         tag: {
-            color: color_scheme.ramps.blue(0.5).hex(),
+            color: theme.ramps.blue(0.5).hex(),
         },
         attribute: {
-            color: color_scheme.ramps.blue(0.5).hex(),
+            color: theme.ramps.blue(0.5).hex(),
         },
         property: {
-            color: color_scheme.ramps.blue(0.5).hex(),
+            color: theme.ramps.blue(0.5).hex(),
         },
         constant: {
             color: color.constant,
@@ -307,17 +308,18 @@ function build_default_syntax(color_scheme: ColorScheme): Syntax {
     return default_syntax
 }
 
-function merge_syntax(
-    default_syntax: Syntax,
-    color_scheme: ColorScheme
-): Syntax {
-    if (!color_scheme.syntax) {
+export function build_syntax(): Syntax {
+    const theme = useTheme()
+
+    const default_syntax: Syntax = build_default_syntax()
+
+    if (!theme.syntax) {
         return default_syntax
     }
 
-    return deepmerge<Syntax, Partial<ThemeSyntax>>(
+    const syntax = deepmerge<Syntax, Partial<ThemeSyntax>>(
         default_syntax,
-        color_scheme.syntax,
+        theme.syntax,
         {
             arrayMerge: (destinationArray, sourceArray) => [
                 ...destinationArray,
@@ -325,12 +327,6 @@ function merge_syntax(
             ],
         }
     )
-}
-
-export function build_syntax(color_scheme: ColorScheme): Syntax {
-    const default_syntax: Syntax = build_default_syntax(color_scheme)
-
-    const syntax = merge_syntax(default_syntax, color_scheme)
 
     return syntax
 }

styles/src/theme/theme_config.ts 🔗

@@ -66,35 +66,10 @@ type ThemeConfigProperties = ThemeMeta & {
     override: ThemeConfigOverrides
 }
 
-// This should be the format a theme is defined as
 export type ThemeConfig = {
     [K in keyof ThemeConfigProperties]: ThemeConfigProperties[K]
 }
 
-interface ThemeColors {
-    neutral: string[]
-    red: string[]
-    orange: string[]
-    yellow: string[]
-    green: string[]
-    cyan: string[]
-    blue: string[]
-    violet: string[]
-    magenta: string[]
-}
-
-type ThemeSyntax = Required<Syntax>
-
-export type ThemeProperties = ThemeMeta & {
-    color: ThemeColors
-    syntax: ThemeSyntax
-}
-
-// This should be a theme after all its properties have been resolved
-export type Theme = {
-    [K in keyof ThemeProperties]: ThemeProperties[K]
-}
-
 export enum ThemeAppearance {
     Light = "light",
     Dark = "dark",
@@ -104,45 +79,3 @@ export enum ThemeLicenseType {
     MIT = "MIT",
     Apache2 = "Apache License 2.0",
 }
-
-export type ThemeFamilyItem =
-    | ThemeConfig
-    | { light: ThemeConfig; dark: ThemeConfig }
-
-type ThemeFamilyProperties = Partial<Omit<ThemeMeta, "name" | "appearance">> & {
-    name: string
-    default: ThemeFamilyItem
-    variants: {
-        [key: string]: ThemeFamilyItem
-    }
-}
-
-// Idea: A theme family is a collection of themes that share the same name
-// For example, a theme family could be `One Dark` and have a `light` and `dark` variant
-// The Ayu family could have `light`, `mirage`, and `dark` variants
-
-type ThemeFamily = {
-    [K in keyof ThemeFamilyProperties]: ThemeFamilyProperties[K]
-}
-
-/** The collection of all themes
- *
- * Example:
- * ```ts
- * {
- *   one_dark,
- *   one_light,
- *     ayu: {
- *     name: 'Ayu',
- *     default: 'ayu_mirage',
- *     variants: {
- *       light: 'ayu_light',
- *       mirage: 'ayu_mirage',
- *       dark: 'ayu_dark',
- *     },
- *   },
- *  ...
- * }
- * ```
- */
-export type ThemeIndex = Record<string, ThemeFamily | ThemeConfig>

styles/src/theme/tokens/layer.ts 🔗

@@ -1,5 +1,5 @@
 import { SingleColorToken } from "@tokens-studio/types"
-import { Layer, Style, StyleSet } from "../color_scheme"
+import { Layer, Style, StyleSet } from "../create_theme"
 import { color_token } from "./token"
 
 interface StyleToken {

styles/src/theme/tokens/players.ts 🔗

@@ -1,7 +1,7 @@
 import { SingleColorToken } from "@tokens-studio/types"
 import { color_token } from "./token"
-import { Players } from "../color_scheme"
-import { useTheme } from "@/src/common"
+import { Players } from "../create_theme"
+import { useTheme } from "../../../src/common"
 
 export type PlayerToken = Record<"selection" | "cursor", SingleColorToken>
 

styles/src/theme/tokens/color_scheme.ts → styles/src/theme/tokens/theme.ts 🔗

@@ -5,19 +5,18 @@ import {
     TokenTypes,
 } from "@tokens-studio/types"
 import {
-    ColorScheme,
     Shadow,
     SyntaxHighlightStyle,
     ThemeSyntax,
-} from "../color_scheme"
+} from "../create_theme"
 import { LayerToken, layer_token } from "./layer"
 import { PlayersToken, players_token } from "./players"
 import { color_token } from "./token"
 import { Syntax } from "../syntax"
 import editor from "../../style_tree/editor"
-import { useTheme } from "@/src/common"
+import { useTheme } from "../../../src/common"
 
-interface ColorSchemeTokens {
+interface ThemeTokens {
     name: SingleOtherToken
     appearance: SingleOtherToken
     lowest: LayerToken
@@ -71,13 +70,13 @@ function syntax_highlight_style_color_tokens(
     }, {} as ThemeSyntaxColorTokens)
 }
 
-const syntax_tokens = (): ColorSchemeTokens["syntax"] => {
+const syntax_tokens = (): ThemeTokens["syntax"] => {
     const syntax = editor().syntax
 
     return syntax_highlight_style_color_tokens(syntax)
 }
 
-export function theme_tokens(): ColorSchemeTokens {
+export function theme_tokens(): ThemeTokens {
     const theme = useTheme()
 
     return {