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