diff --git a/apps/web/package.json b/apps/web/package.json index 61bbb0d14..6bd361a9c 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -34,6 +34,7 @@ "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "@fontsource-variable/manrope": "^5.3.0", + "@lezer/highlight": "^1.2.4", "@lingui/core": "^6.8.0", "@lingui/react": "^6.8.0", "@orpc/client": "^1.15.4", diff --git a/apps/web/src/features/resume/stylesheet/editor.tsx b/apps/web/src/features/resume/stylesheet/editor.tsx index c8830710a..2d55afd11 100644 --- a/apps/web/src/features/resume/stylesheet/editor.tsx +++ b/apps/web/src/features/resume/stylesheet/editor.tsx @@ -6,7 +6,7 @@ import type { SemanticCssColorToken } from "./color-tokens"; import type { SemanticCssEditorMetadata } from "./protocol"; import { defaultKeymap, indentWithTab } from "@codemirror/commands"; import { css } from "@codemirror/lang-css"; -import { defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language"; +import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; import { Annotation, Compartment, EditorState, Prec, Transaction } from "@codemirror/state"; import { drawSelection, @@ -16,6 +16,7 @@ import { keymap, lineNumbers, } from "@codemirror/view"; +import { tags } from "@lezer/highlight"; import { t } from "@lingui/core/macro"; import { Trans } from "@lingui/react/macro"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; @@ -54,6 +55,18 @@ type EditorCompartments = { intelligence: Compartment; }; +/** CSS in the app's own inks, so it reads the same in light and dark. */ +const highlightStyle = HighlightStyle.define([ + { tag: [tags.comment, tags.meta], color: "var(--ink-3)", fontStyle: "italic" }, + { tag: [tags.tagName, tags.className, tags.labelName], color: "var(--accent-text)" }, + { tag: [tags.propertyName, tags.attributeName], color: "var(--info-text)" }, + { tag: [tags.string, tags.number, tags.unit, tags.color, tags.atom], color: "var(--warn-text)" }, + { tag: [tags.keyword, tags.modifier, tags.definitionKeyword, tags.controlKeyword], color: "var(--danger-text)" }, + { tag: [tags.variableName, tags.function(tags.variableName)], color: "var(--ink)", fontWeight: "500" }, + { tag: [tags.punctuation, tags.operator, tags.bracket], color: "var(--ink-2)" }, + { tag: tags.invalid, color: "var(--danger-text)", textDecoration: "underline wavy" }, +]); + const editorTheme = (dark: boolean): Extension => EditorView.theme( { @@ -65,7 +78,7 @@ const editorTheme = (dark: boolean): Extension => }, ".cm-scroller": { overflow: "auto", - fontFamily: '"JetBrains Mono Variable", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace', + fontFamily: "var(--font-mono)", lineHeight: "1.5", }, ".cm-content": { minHeight: "100%", padding: "0.75rem 0" }, @@ -162,7 +175,7 @@ export function StylesheetCodeEditor({ drawSelection(), highlightActiveLine(), css(), - syntaxHighlighting(defaultHighlightStyle, { fallback: true }), + syntaxHighlighting(highlightStyle), EditorView.editorAttributes.of({ dir: "ltr" }), EditorView.contentAttributes.of({ "aria-label": initial.label, dir: "ltr", spellcheck: "false" }), Prec.high( diff --git a/apps/web/src/features/resume/stylesheet/legacy-banner.tsx b/apps/web/src/features/resume/stylesheet/legacy-banner.tsx index 8934da52c..e5160df5d 100644 --- a/apps/web/src/features/resume/stylesheet/legacy-banner.tsx +++ b/apps/web/src/features/resume/stylesheet/legacy-banner.tsx @@ -21,7 +21,7 @@ export function LegacyStylesheetBanner({ disabled, onActivate }: LegacyStyleshee
diff --git a/apps/web/src/features/resume/stylesheet/status.tsx b/apps/web/src/features/resume/stylesheet/status.tsx index 70acafc6b..11e93d3e0 100644 --- a/apps/web/src/features/resume/stylesheet/status.tsx +++ b/apps/web/src/features/resume/stylesheet/status.tsx @@ -23,19 +23,19 @@ export function StylesheetStatus({ mode, status, diagnostics }: StylesheetStatus