diff --git a/apps/web/src/styles/code-highlight-dark.css b/apps/web/src/styles/code-highlight-dark.css new file mode 100644 index 00000000..312af5d5 --- /dev/null +++ b/apps/web/src/styles/code-highlight-dark.css @@ -0,0 +1,88 @@ +/* + * Lowlight always emits the same Highlight.js token classes. The default + * GitHub import in globals.css covers light mode; scope GitHub Dark's token + * palette to EdgeEver's explicit app theme so a user override does not depend + * on the operating-system color scheme. + */ +:root.dark .ProseMirror .edgeever-code-block .hljs { + background: transparent; + color: #c9d1d9; +} + +:root.dark .ProseMirror .edgeever-code-block .hljs-doctag, +:root.dark .ProseMirror .edgeever-code-block .hljs-keyword, +:root.dark .ProseMirror .edgeever-code-block .hljs-meta .hljs-keyword, +:root.dark .ProseMirror .edgeever-code-block .hljs-template-tag, +:root.dark .ProseMirror .edgeever-code-block .hljs-template-variable, +:root.dark .ProseMirror .edgeever-code-block .hljs-type, +:root.dark .ProseMirror .edgeever-code-block .hljs-variable.language_ { + color: #ff7b72; +} + +:root.dark .ProseMirror .edgeever-code-block .hljs-title, +:root.dark .ProseMirror .edgeever-code-block .hljs-title.class_, +:root.dark .ProseMirror .edgeever-code-block .hljs-title.class_.inherited__, +:root.dark .ProseMirror .edgeever-code-block .hljs-title.function_ { + color: #d2a8ff; +} + +:root.dark .ProseMirror .edgeever-code-block .hljs-attr, +:root.dark .ProseMirror .edgeever-code-block .hljs-attribute, +:root.dark .ProseMirror .edgeever-code-block .hljs-literal, +:root.dark .ProseMirror .edgeever-code-block .hljs-meta, +:root.dark .ProseMirror .edgeever-code-block .hljs-number, +:root.dark .ProseMirror .edgeever-code-block .hljs-operator, +:root.dark .ProseMirror .edgeever-code-block .hljs-variable, +:root.dark .ProseMirror .edgeever-code-block .hljs-selector-attr, +:root.dark .ProseMirror .edgeever-code-block .hljs-selector-class, +:root.dark .ProseMirror .edgeever-code-block .hljs-selector-id { + color: #79c0ff; +} + +:root.dark .ProseMirror .edgeever-code-block .hljs-regexp, +:root.dark .ProseMirror .edgeever-code-block .hljs-string, +:root.dark .ProseMirror .edgeever-code-block .hljs-meta .hljs-string { + color: #a5d6ff; +} + +:root.dark .ProseMirror .edgeever-code-block .hljs-built_in, +:root.dark .ProseMirror .edgeever-code-block .hljs-symbol { + color: #ffa657; +} + +:root.dark .ProseMirror .edgeever-code-block .hljs-comment, +:root.dark .ProseMirror .edgeever-code-block .hljs-code, +:root.dark .ProseMirror .edgeever-code-block .hljs-formula { + color: #8b949e; +} + +:root.dark .ProseMirror .edgeever-code-block .hljs-name, +:root.dark .ProseMirror .edgeever-code-block .hljs-quote, +:root.dark .ProseMirror .edgeever-code-block .hljs-selector-tag, +:root.dark .ProseMirror .edgeever-code-block .hljs-selector-pseudo { + color: #7ee787; +} + +:root.dark .ProseMirror .edgeever-code-block .hljs-subst, +:root.dark .ProseMirror .edgeever-code-block .hljs-emphasis, +:root.dark .ProseMirror .edgeever-code-block .hljs-strong { + color: #c9d1d9; +} + +:root.dark .ProseMirror .edgeever-code-block .hljs-section { + color: #58a6ff; +} + +:root.dark .ProseMirror .edgeever-code-block .hljs-bullet { + color: #f2cc60; +} + +:root.dark .ProseMirror .edgeever-code-block .hljs-addition { + background-color: #033a16; + color: #aff5b4; +} + +:root.dark .ProseMirror .edgeever-code-block .hljs-deletion { + background-color: #67060c; + color: #ffdcd7; +} diff --git a/apps/web/src/styles/code-highlight-theme.test.mjs b/apps/web/src/styles/code-highlight-theme.test.mjs new file mode 100644 index 00000000..649a984a --- /dev/null +++ b/apps/web/src/styles/code-highlight-theme.test.mjs @@ -0,0 +1,38 @@ +import { describe, expect, test } from "bun:test"; +import { readFileSync } from "node:fs"; + +const globals = readFileSync(new URL("./globals.css", import.meta.url), "utf8"); +const darkTheme = readFileSync(new URL("./code-highlight-dark.css", import.meta.url), "utf8"); + +describe("rich-text code highlight themes", () => { + test("loads the light palette before the scoped dark override", () => { + const lightImport = '@import "highlight.js/styles/github.css";'; + const darkImport = '@import "./code-highlight-dark.css";'; + + expect(globals).toContain(lightImport); + expect(globals).toContain(darkImport); + expect(globals.indexOf(darkImport)).toBeGreaterThan(globals.indexOf(lightImport)); + }); + + test("scopes GitHub Dark token colors to dark rich-text code blocks", () => { + expect(darkTheme).toContain(":root.dark .ProseMirror .edgeever-code-block .hljs"); + expect(darkTheme).toContain("background: transparent;"); + + for (const token of [ + "keyword", + "title", + "number", + "string", + "built_in", + "comment", + "selector-tag", + "subst", + "section", + "bullet", + "addition", + "deletion", + ]) { + expect(darkTheme).toContain(`.edgeever-code-block .hljs-${token}`); + } + }); +}); diff --git a/apps/web/src/styles/globals.css b/apps/web/src/styles/globals.css index 685b189c..c512a5d2 100644 --- a/apps/web/src/styles/globals.css +++ b/apps/web/src/styles/globals.css @@ -1,5 +1,6 @@ @import "highlight.js/styles/github.css"; @import "./editor-themes/index.css"; +@import "./code-highlight-dark.css"; @tailwind base; @tailwind components;