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>