vscode-bauhaus-theme 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,146 @@
1
+ import colors from "../colors.json" with { type: "json" };
2
+ import {
3
+ fit,
4
+ fromOklch,
5
+ mix,
6
+ mixHue,
7
+ mostContrasted,
8
+ toOklch,
9
+ } from "./color.js";
10
+
11
+ const { white, black, red, blue, green, yellow, "grey-6d": grey6d } = colors;
12
+
13
+ // The source only has 3 hues legible as text on light and none on dark (yellow aside): the
14
+ // secondary hues are OKLCH midpoints of the primaries, keeping chroma so they don't turn grey.
15
+ const HUES = {
16
+ red,
17
+ orange: mixHue(red, yellow),
18
+ yellow,
19
+ green,
20
+ cyan: mixHue(blue, green),
21
+ blue,
22
+ violet: mixHue(red, blue),
23
+ };
24
+
25
+ const FILLS = { red, blue, green, yellow };
26
+
27
+ const mapValues = (object, fn) =>
28
+ Object.fromEntries(
29
+ Object.entries(object).map(([key, value]) => [key, fn(value)]),
30
+ );
31
+
32
+ // Editor and chrome share the warm hue of "black" and are separated by lightness only, as in
33
+ // Material High Contrast (editor/side bar 1.23:1). "black" is grey-22 tinted (1.01:1): lifting it
34
+ // keeps the tint.
35
+ // Light surfaces have no source match: a paper tint at the same hue.
36
+ // Lines (borders, guides, selected rows) keep the grey-40 on grey-22 step: 1.53:1.
37
+ const [, , WARM_HUE] = toOklch(black);
38
+ const darkEditor = fit(black, black, 1.23);
39
+ const lightEditor = fromOklch([0.945, 0.015, WARM_HUE]);
40
+
41
+ const SURFACES = {
42
+ dark: {
43
+ editor: darkEditor,
44
+ chrome: black,
45
+ line: fit(darkEditor, darkEditor, 1.53),
46
+ text: white,
47
+ muted: grey6d,
48
+ },
49
+ light: {
50
+ editor: lightEditor,
51
+ chrome: fit(lightEditor, lightEditor, 1.16),
52
+ line: fit(lightEditor, lightEditor, 1.53),
53
+ text: black,
54
+ muted: grey6d,
55
+ },
56
+ };
57
+
58
+ const AA = 4.5;
59
+ const AAA = 7;
60
+ // Source blue, green and cyan are greyish (OKLCH chroma ~0.07): too close to the text color once dark.
61
+ const INK = { exact: true, chroma: 1.6 };
62
+
63
+ /**
64
+ * @typedef {object} Palette
65
+ * @property {string} id
66
+ * @property {"dark" | "light"} type
67
+ * @property {Backgrounds} bg
68
+ * @property {Foregrounds} fg
69
+ * @property {Hues} ink Hues for text and marks on backgrounds.
70
+ * @property {Hues} bright Terminal bright variants.
71
+ * @property {Fills} fill Hues as solid surfaces.
72
+ * @property {Fills} onFill Text on each fill.
73
+ */
74
+
75
+ /**
76
+ * @typedef {object} Backgrounds
77
+ * @property {string} editor
78
+ * @property {string} chrome Side bar, panels, title and activity bars.
79
+ * @property {string} line Borders, guides, selected rows.
80
+ */
81
+
82
+ /**
83
+ * @typedef {object} Foregrounds
84
+ * @property {string} default
85
+ * @property {string} muted
86
+ */
87
+
88
+ /**
89
+ * @typedef {object} Hues
90
+ * @property {string} red
91
+ * @property {string} orange
92
+ * @property {string} yellow
93
+ * @property {string} green
94
+ * @property {string} cyan
95
+ * @property {string} blue
96
+ * @property {string} violet
97
+ */
98
+
99
+ /**
100
+ * @typedef {object} Fills
101
+ * @property {string} red
102
+ * @property {string} blue
103
+ * @property {string} green
104
+ * @property {string} yellow
105
+ */
106
+
107
+ /**
108
+ * Source colors used as is.
109
+ *
110
+ * @param {"dark" | "light"} type
111
+ * @returns {Palette}
112
+ */
113
+ function source(type) {
114
+ const { editor, chrome, line, text, muted } = SURFACES[type];
115
+ return {
116
+ id: type,
117
+ type,
118
+ bg: { editor, chrome, line },
119
+ fg: { default: text, muted },
120
+ ink: HUES,
121
+ bright: mapValues(HUES, (hue) => mix(hue, text, 0.3)),
122
+ fill: FILLS,
123
+ onFill: mapValues(FILLS, (fill) => mostContrasted(fill, [white, black])),
124
+ };
125
+ }
126
+
127
+ /**
128
+ * Source hues, saturated, at the lightness closest to the backgrounds that
129
+ * reaches WCAG 2.0 AA against editor and chrome. Equal contrast keeps hues
130
+ * apart from the text color on both sides.
131
+ *
132
+ * @param {"dark" | "light"} type
133
+ * @returns {Palette}
134
+ */
135
+ function wcag(type) {
136
+ const base = source(type);
137
+ const backgrounds = [base.bg.editor, base.bg.chrome];
138
+ return {
139
+ ...base,
140
+ fg: { ...base.fg, muted: fit(base.fg.muted, backgrounds, AA) },
141
+ ink: mapValues(HUES, (hue) => fit(hue, backgrounds, AA, INK)),
142
+ bright: mapValues(HUES, (hue) => fit(hue, backgrounds, AAA, INK)),
143
+ };
144
+ }
145
+
146
+ export const palettes = [wcag("dark"), wcag("light")];
package/src/syntax.js ADDED
@@ -0,0 +1,281 @@
1
+ /** @typedef {import("./palettes.js").Palette} Palette */
2
+
3
+ /**
4
+ * Syntax roles, modelled on Community Material Theme High Contrast with Bauhaus
5
+ * hues: Material purple (keywords) → red accent, Material red/coral (params,
6
+ * tags, constants) → violet, other hues keep their role.
7
+ *
8
+ * @param {Palette} p
9
+ */
10
+ export const roles = (p) => ({
11
+ text: p.fg.default,
12
+ comment: p.fg.muted,
13
+ keyword: p.ink.red,
14
+ operator: p.ink.cyan,
15
+ function: p.ink.blue,
16
+ type: p.ink.yellow,
17
+ string: p.ink.green,
18
+ constant: p.ink.orange,
19
+ variable: p.ink.violet,
20
+ invalid: p.ink.red,
21
+ });
22
+
23
+ const rule = (name, scope, foreground, fontStyle) => ({
24
+ name,
25
+ scope,
26
+ settings: {
27
+ ...(foreground && { foreground }),
28
+ ...(fontStyle !== undefined && { fontStyle }),
29
+ },
30
+ });
31
+
32
+ // Material cycles JSON key colors per nesting depth.
33
+ const jsonKeys = (colors) =>
34
+ colors.map((foreground, depth) =>
35
+ rule(
36
+ `JSON key depth ${depth + 1}`,
37
+ `source.json ${"meta.structure.dictionary.json ".repeat(depth + 1)}support.type.property-name.json`,
38
+ foreground,
39
+ ),
40
+ );
41
+
42
+ /**
43
+ * TextMate rules. Later rules win on equal specificity.
44
+ *
45
+ * @param {Palette} p
46
+ */
47
+ export function tokenColors(p) {
48
+ const r = roles(p);
49
+ return [
50
+ rule(
51
+ "Text",
52
+ [
53
+ "variable",
54
+ "variable.other.readwrite",
55
+ "meta.definition.variable",
56
+ "support.variable.property",
57
+ "variable.other.property",
58
+ "variable.other.object.property",
59
+ "constant.other.color",
60
+ "support.type.property-name.css",
61
+ ],
62
+ r.text,
63
+ ),
64
+ rule(
65
+ "Comment",
66
+ ["comment", "punctuation.definition.comment", "string.quoted.docstring"],
67
+ r.comment,
68
+ "italic",
69
+ ),
70
+ rule(
71
+ "Keyword",
72
+ [
73
+ "keyword",
74
+ "storage.type",
75
+ "storage.modifier",
76
+ "keyword.other.important",
77
+ ],
78
+ r.keyword,
79
+ ),
80
+ rule("Control flow", ["keyword.control"], r.operator, "italic"),
81
+ rule(
82
+ "Operator, punctuation",
83
+ [
84
+ "keyword.operator",
85
+ "punctuation",
86
+ "meta.brace",
87
+ "punctuation.definition.tag",
88
+ "punctuation.separator.inheritance.php",
89
+ ],
90
+ r.operator,
91
+ ),
92
+ rule(
93
+ "Regexp, escape, template",
94
+ [
95
+ "string.regexp",
96
+ "constant.character.escape",
97
+ "keyword.other.template",
98
+ "keyword.other.substitution",
99
+ "punctuation.section.embedded",
100
+ "punctuation.definition.template-expression",
101
+ ],
102
+ r.operator,
103
+ ),
104
+ rule(
105
+ "Function",
106
+ [
107
+ "entity.name.function",
108
+ "variable.function",
109
+ "support.function",
110
+ "meta.function-call entity.name.function",
111
+ "keyword.other.special-method",
112
+ "variable.function.constructor",
113
+ ],
114
+ r.function,
115
+ ),
116
+ rule(
117
+ "Decorator",
118
+ [
119
+ "meta.decorator entity.name.function",
120
+ "meta.decorator variable.other",
121
+ "punctuation.decorator",
122
+ "entity.name.function.decorator",
123
+ ],
124
+ r.function,
125
+ "italic",
126
+ ),
127
+ rule(
128
+ "Type",
129
+ [
130
+ "entity.name",
131
+ "entity.name.type",
132
+ "entity.name.class",
133
+ "entity.name.namespace",
134
+ "support.type",
135
+ "support.class",
136
+ "support.other.namespace",
137
+ "entity.other.attribute-name.class",
138
+ "constant.other.reference.link.markdown",
139
+ ],
140
+ r.type,
141
+ ),
142
+ rule("Inherited class", ["entity.other.inherited-class"], r.type, "italic"),
143
+ rule(
144
+ "String",
145
+ ["string", "constant.other.symbol", "constant.other.key"],
146
+ r.string,
147
+ ),
148
+ rule(
149
+ "Constant",
150
+ [
151
+ "constant.numeric",
152
+ "constant.language",
153
+ "support.constant",
154
+ "constant.character",
155
+ "keyword.other.unit",
156
+ "variable.other.enummember",
157
+ ],
158
+ r.constant,
159
+ ),
160
+ rule(
161
+ "Tag, constant variable",
162
+ [
163
+ "entity.name.tag",
164
+ "meta.tag.sgml",
165
+ "variable.other.constant",
166
+ "support.other.variable",
167
+ "entity.name.tag.css",
168
+ ],
169
+ r.variable,
170
+ ),
171
+ rule(
172
+ "Parameter",
173
+ ["variable.parameter", "meta.parameters variable.other"],
174
+ r.variable,
175
+ ),
176
+ rule(
177
+ "Language variable",
178
+ ["variable.language", "variable.parameter.function.language.special"],
179
+ r.variable,
180
+ "italic",
181
+ ),
182
+ rule("Attribute", ["entity.other.attribute-name"], r.keyword, "italic"),
183
+ rule(
184
+ "CSS id, pseudo",
185
+ [
186
+ "entity.other.attribute-name.id",
187
+ "entity.other.attribute-name.pseudo-class",
188
+ "entity.other.attribute-name.pseudo-element",
189
+ ],
190
+ r.constant,
191
+ ),
192
+ rule("Invalid", ["invalid", "invalid.illegal"], r.invalid, "underline"),
193
+ rule("Deprecated", ["invalid.deprecated"], r.comment, "strikethrough"),
194
+ rule("Link", ["*url*", "*link*", "*uri*"], undefined, "underline"),
195
+ ...jsonKeys([
196
+ r.keyword,
197
+ r.type,
198
+ r.constant,
199
+ r.variable,
200
+ r.function,
201
+ r.string,
202
+ ]),
203
+ rule(
204
+ "Markdown heading",
205
+ [
206
+ "markup.heading",
207
+ "markup.heading entity.name",
208
+ "punctuation.definition.heading.markdown",
209
+ ],
210
+ r.string,
211
+ "bold",
212
+ ),
213
+ rule("Markdown bold", ["markup.bold"], r.variable, "bold"),
214
+ rule("Markdown italic", ["markup.italic"], r.variable, "italic"),
215
+ rule(
216
+ "Markdown strike",
217
+ ["markup.strikethrough"],
218
+ undefined,
219
+ "strikethrough",
220
+ ),
221
+ rule("Markdown code", ["markup.inline.raw", "markup.raw.block"], r.keyword),
222
+ rule("Markdown fenced code", ["markup.fenced_code.block.markdown"], r.text),
223
+ rule("Markdown quote", ["markup.quote"], r.comment, "italic"),
224
+ rule(
225
+ "Markdown link text",
226
+ [
227
+ "string.other.link.title.markdown",
228
+ "string.other.link.description.markdown",
229
+ ],
230
+ r.function,
231
+ ),
232
+ rule("Markdown link url", ["markup.underline.link"], r.operator),
233
+ rule(
234
+ "Markdown list",
235
+ [
236
+ "punctuation.definition.list.begin.markdown",
237
+ "beginning.punctuation.definition.list.markdown",
238
+ ],
239
+ r.operator,
240
+ ),
241
+ rule("Separator", ["meta.separator"], r.comment, "bold"),
242
+ rule("Diff inserted", ["markup.inserted"], r.string),
243
+ rule("Diff deleted", ["markup.deleted"], r.invalid),
244
+ rule("Diff changed", ["markup.changed"], r.type),
245
+ ];
246
+ }
247
+
248
+ /**
249
+ * Semantic tokens refine TextMate where language servers know more (e.g.
250
+ * references to parameters). Unlisted selectors fall back to the TextMate scope
251
+ * mapping.
252
+ *
253
+ * @param {Palette} p
254
+ */
255
+ export function semanticTokenColors(p) {
256
+ const r = roles(p);
257
+ return {
258
+ namespace: r.type,
259
+ type: r.type,
260
+ class: r.type,
261
+ interface: r.type,
262
+ enum: r.type,
263
+ struct: r.type,
264
+ typeParameter: { foreground: r.type, italic: true },
265
+ function: r.function,
266
+ method: r.function,
267
+ decorator: { foreground: r.function, italic: true },
268
+ macro: r.constant,
269
+ parameter: r.variable,
270
+ variable: r.text,
271
+ // Material only colors constant declarations; colouring every reference would flood the code.
272
+ "variable.readonly": r.text,
273
+ "variable.readonly.declaration": r.variable,
274
+ "variable.readonly.defaultLibrary": r.constant,
275
+ property: r.text,
276
+ enumMember: r.constant,
277
+ event: r.variable,
278
+ label: r.comment,
279
+ "*.deprecated": { fontStyle: "strikethrough" },
280
+ };
281
+ }