themeConfig.ts

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