themeConfig.ts

  1import { Scale, Color } from "chroma-js"
  2import { Syntax } from "./syntax"
  3
  4interface ThemeMeta {
  5    /** The name of the theme */
  6    name: string
  7    /** The theme's appearance. Either `light` or `dark`. */
  8    appearance: ThemeAppearance
  9    /** The author of the theme
 10     *
 11     * Ideally formatted as `Full Name <email>`
 12     *
 13     * Example: `John Doe <john@doe.com>`
 14     */
 15    author: string
 16    /** SPDX License string
 17     *
 18     * Example: `MIT`
 19     */
 20    licenseType?: string | ThemeLicenseType
 21    licenseUrl?: string
 22    licenseFile: string
 23    themeUrl?: string
 24}
 25
 26export type ThemeFamilyMeta = Pick<
 27    ThemeMeta,
 28    "name" | "author" | "licenseType" | "licenseUrl"
 29>
 30
 31export interface ThemeConfigInputColors {
 32    neutral: Scale<Color>
 33    red: Scale<Color>
 34    orange: Scale<Color>
 35    yellow: Scale<Color>
 36    green: Scale<Color>
 37    cyan: Scale<Color>
 38    blue: Scale<Color>
 39    violet: Scale<Color>
 40    magenta: Scale<Color>
 41}
 42
 43export type ThemeConfigInputColorsKeys = keyof ThemeConfigInputColors
 44
 45/** Allow any part of a syntax highlight style to be overriden by the theme
 46 *
 47 * Example:
 48 * ```ts
 49 * override: {
 50 *   syntax: {
 51 *     boolean: {
 52 *       underline: true,
 53 *     },
 54 *   },
 55 * }
 56 * ```
 57 */
 58export type ThemeConfigInputSyntax = Partial<Syntax>
 59
 60interface ThemeConfigOverrides {
 61    syntax: ThemeConfigInputSyntax
 62}
 63
 64type ThemeConfigProperties = ThemeMeta & {
 65    inputColor: ThemeConfigInputColors
 66    override: ThemeConfigOverrides
 67}
 68
 69// This should be the format a theme is defined as
 70export type ThemeConfig = {
 71    [K in keyof ThemeConfigProperties]: ThemeConfigProperties[K]
 72}
 73
 74interface ThemeColors {
 75    neutral: string[]
 76    red: string[]
 77    orange: string[]
 78    yellow: string[]
 79    green: string[]
 80    cyan: string[]
 81    blue: string[]
 82    violet: string[]
 83    magenta: string[]
 84}
 85
 86type ThemeSyntax = Required<Syntax>
 87
 88export type ThemeProperties = ThemeMeta & {
 89    color: ThemeColors
 90    syntax: ThemeSyntax
 91}
 92
 93// This should be a theme after all its properties have been resolved
 94export type Theme = {
 95    [K in keyof ThemeProperties]: ThemeProperties[K]
 96}
 97
 98export enum ThemeAppearance {
 99    Light = "light",
100    Dark = "dark",
101}
102
103export enum ThemeLicenseType {
104    MIT = "MIT",
105    Apache2 = "Apache License 2.0",
106}
107
108export type ThemeFamilyItem =
109    | ThemeConfig
110    | { light: ThemeConfig; dark: ThemeConfig }
111
112type ThemeFamilyProperties = Partial<Omit<ThemeMeta, "name" | "appearance">> & {
113    name: string
114    default: ThemeFamilyItem
115    variants: {
116        [key: string]: ThemeFamilyItem
117    }
118}
119
120// Idea: A theme family is a collection of themes that share the same name
121// For example, a theme family could be `One Dark` and have a `light` and `dark` variant
122// The Ayu family could have `light`, `mirage`, and `dark` variants
123
124type ThemeFamily = {
125    [K in keyof ThemeFamilyProperties]: ThemeFamilyProperties[K]
126}
127
128/** The collection of all themes
129 *
130 * Example:
131 * ```ts
132 * {
133 *   one_dark,
134 *   one_light,
135 *     ayu: {
136 *     name: 'Ayu',
137 *     default: 'ayu_mirage',
138 *     variants: {
139 *       light: 'ayu_light',
140 *       mirage: 'ayu_mirage',
141 *       dark: 'ayu_dark',
142 *     },
143 *   },
144 *  ...
145 * }
146 * ```
147 */
148export type ThemeIndex = Record<string, ThemeFamily | ThemeConfig>