import { EditorView } from "@codemirror/view"; import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; import { tags as t } from "@lezer/highlight"; import type { Extension } from "@codemirror/state"; /* ─────────────────────────────────────────────────────────── Tusk "Graphite & Honey" CodeMirror theme. Palette mirrors the design tokens in styles/globals.css so the SQL editor sits seamlessly inside the warm graphite workstation. ─────────────────────────────────────────────────────────── */ const c = { bg: "oklch(0.186 0.006 75)", surface: "oklch(0.205 0.007 75)", fg: "oklch(0.9 0.013 80)", faint: "oklch(0.52 0.012 75)", gutter: "oklch(0.46 0.011 75)", gutterActive: "oklch(0.74 0.012 80)", cursor: "oklch(0.84 0.13 82)", selection: "oklch(0.808 0.124 82 / 22%)", activeLine: "oklch(0.808 0.124 82 / 5%)", activeGutter: "oklch(0.808 0.124 82 / 9%)", matchBg: "oklch(0.808 0.124 82 / 18%)", // syntax keyword: "oklch(0.82 0.125 82)", // honey — SELECT, FROM, WHERE string: "oklch(0.76 0.13 152)", // green number: "oklch(0.74 0.12 222)", // cyan-blue func: "oklch(0.74 0.15 305)", // violet — built-ins type: "oklch(0.74 0.12 200)", // teal-cyan — types comment: "oklch(0.5 0.012 75)", // muted, italic operator: "oklch(0.74 0.013 80)", bracket: "oklch(0.66 0.012 78)", invalid: "oklch(0.66 0.2 24)", }; const tuskEditorTheme = EditorView.theme( { "&": { color: c.fg, backgroundColor: c.bg, }, ".cm-content": { caretColor: c.cursor, fontFamily: "var(--font-mono)", padding: "8px 0", }, ".cm-cursor, .cm-dropCursor": { borderLeftColor: c.cursor, borderLeftWidth: "2px" }, "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": { backgroundColor: c.selection }, ".cm-activeLine": { backgroundColor: c.activeLine }, ".cm-gutters": { backgroundColor: c.bg, color: c.gutter, border: "none", borderRight: "1px solid oklch(0.34 0.011 75 / 50%)", }, ".cm-activeLineGutter": { backgroundColor: c.activeGutter, color: c.gutterActive, }, ".cm-foldGutter .cm-gutterElement": { color: c.faint }, ".cm-selectionMatch": { backgroundColor: c.matchBg }, "&.cm-focused .cm-matchingBracket": { backgroundColor: c.matchBg, outline: "1px solid oklch(0.808 0.124 82 / 45%)", borderRadius: "2px", }, ".cm-line": { padding: "0 4px 0 8px" }, ".cm-scroller": { fontFamily: "var(--font-mono)" }, ".cm-panels": { backgroundColor: c.surface, color: c.fg }, ".cm-searchMatch": { backgroundColor: "oklch(0.78 0.135 65 / 28%)", outline: "1px solid oklch(0.78 0.135 65 / 50%)", }, ".cm-searchMatch.cm-searchMatch-selected": { backgroundColor: "oklch(0.808 0.124 82 / 35%)", }, }, { dark: true } ); const tuskHighlightStyle = HighlightStyle.define([ { tag: [t.keyword, t.operatorKeyword, t.modifier], color: c.keyword, fontWeight: "500" }, { tag: [t.string, t.special(t.string), t.character], color: c.string }, { tag: [t.number, t.bool, t.null], color: c.number }, { tag: [t.function(t.variableName), t.function(t.propertyName)], color: c.func }, { tag: [t.typeName, t.className, t.namespace], color: c.type }, { tag: [t.comment, t.lineComment, t.blockComment], color: c.comment, fontStyle: "italic" }, { tag: [t.operator, t.compareOperator, t.arithmeticOperator, t.logicOperator], color: c.operator }, { tag: [t.bracket, t.paren, t.squareBracket, t.brace, t.punctuation], color: c.bracket }, { tag: [t.propertyName, t.attributeName], color: c.fg }, { tag: [t.variableName, t.name], color: c.fg }, { tag: [t.definitionKeyword], color: c.keyword, fontWeight: "500" }, { tag: [t.invalid], color: c.invalid, textDecoration: "underline wavy" }, ]); /** Full Tusk editor theme: base UI styling + SQL syntax highlighting. */ export const tuskEditorExtensions: Extension = [ tuskEditorTheme, syntaxHighlighting(tuskHighlightStyle), ];