feat: add custom CodeMirror theme with purple accent colors
Replace oneDark theme with custom crispyEditorTheme featuring: - Purple accent (#c9a6eb) for keywords and HTML tags - Matching dark background (#262630) - Applied consistently across editor and reference code blocks 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { LessonEngine } from "./impl/LessonEngine.js";
|
import { LessonEngine } from "./impl/LessonEngine.js";
|
||||||
import { CodeEditor } from "./impl/CodeEditor.js";
|
import { CodeEditor, crispyEditorTheme } from "./impl/CodeEditor.js";
|
||||||
import { renderLesson, renderModuleList, renderLevelIndicator, updateActiveLessonInSidebar } from "./helpers/renderer.js";
|
import { renderLesson, renderModuleList, renderLevelIndicator, updateActiveLessonInSidebar } from "./helpers/renderer.js";
|
||||||
import { loadModules } from "./config/lessons.js";
|
import { loadModules } from "./config/lessons.js";
|
||||||
import { initI18n, t, getLanguage, setLanguage, applyTranslations } from "./i18n.js";
|
import { initI18n, t, getLanguage, setLanguage, applyTranslations } from "./i18n.js";
|
||||||
@@ -10,7 +10,6 @@ import { getRandomTemplate } from "./config/playground-templates.js";
|
|||||||
// CodeMirror imports for syntax highlighting
|
// CodeMirror imports for syntax highlighting
|
||||||
import { EditorState } from "@codemirror/state";
|
import { EditorState } from "@codemirror/state";
|
||||||
import { EditorView } from "@codemirror/view";
|
import { EditorView } from "@codemirror/view";
|
||||||
import { oneDark } from "@codemirror/theme-one-dark";
|
|
||||||
import { html } from "@codemirror/lang-html";
|
import { html } from "@codemirror/lang-html";
|
||||||
import { css } from "@codemirror/lang-css";
|
import { css } from "@codemirror/lang-css";
|
||||||
|
|
||||||
@@ -79,7 +78,7 @@ function highlightSectionCodeBlocks() {
|
|||||||
// Create read-only CodeMirror view
|
// Create read-only CodeMirror view
|
||||||
const state = EditorState.create({
|
const state = EditorState.create({
|
||||||
doc: content,
|
doc: content,
|
||||||
extensions: [langExtension, oneDark, readOnlyTheme, EditorState.readOnly.of(true), EditorView.lineWrapping]
|
extensions: [langExtension, crispyEditorTheme, readOnlyTheme, EditorState.readOnly.of(true), EditorView.lineWrapping]
|
||||||
});
|
});
|
||||||
|
|
||||||
const view = new EditorView({
|
const view = new EditorView({
|
||||||
@@ -2153,7 +2152,7 @@ function highlightReferenceCodeBlocks() {
|
|||||||
const view = new EditorView({
|
const view = new EditorView({
|
||||||
state: EditorState.create({
|
state: EditorState.create({
|
||||||
doc: code,
|
doc: code,
|
||||||
extensions: [isHtml ? html() : css(), oneDark, readOnlyTheme, EditorState.readOnly.of(true), EditorView.editable.of(false)]
|
extensions: [isHtml ? html() : css(), crispyEditorTheme, readOnlyTheme, EditorState.readOnly.of(true), EditorView.editable.of(false)]
|
||||||
}),
|
}),
|
||||||
parent
|
parent
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ const translations = {
|
|||||||
|
|
||||||
// Landing page
|
// Landing page
|
||||||
landingHeroTitle: "Web Programmierung",
|
landingHeroTitle: "Web Programmierung",
|
||||||
landingHeroHighlight: "Selbstständig Coden lernen",
|
landingHeroHighlight: "Selbstständig lernen",
|
||||||
landingHeroSubtitle: "Meistere HTML, CSS und Tailwind durch praktische Übungen mit sofortigem Feedback. Kostenlos und Open Source.",
|
landingHeroSubtitle: "Meistere HTML, CSS und Tailwind durch praktische Übungen mit sofortigem Feedback. Kostenlos und Open Source.",
|
||||||
landingCtaStart: "Jetzt starten",
|
landingCtaStart: "Jetzt starten",
|
||||||
landingWhyTitle: "Warum Code Crispies funktioniert",
|
landingWhyTitle: "Warum Code Crispies funktioniert",
|
||||||
|
|||||||
@@ -5,13 +5,88 @@ import { EditorState, Prec } from "@codemirror/state";
|
|||||||
import { EditorView, keymap, placeholder } from "@codemirror/view";
|
import { EditorView, keymap, placeholder } from "@codemirror/view";
|
||||||
import { defaultKeymap, historyKeymap, indentMore, indentLess, undo, redo } from "@codemirror/commands";
|
import { defaultKeymap, historyKeymap, indentMore, indentLess, undo, redo } from "@codemirror/commands";
|
||||||
import { history } from "@codemirror/commands";
|
import { history } from "@codemirror/commands";
|
||||||
import { oneDark } from "@codemirror/theme-one-dark";
|
|
||||||
import { html } from "@codemirror/lang-html";
|
import { html } from "@codemirror/lang-html";
|
||||||
import { css } from "@codemirror/lang-css";
|
import { css } from "@codemirror/lang-css";
|
||||||
import { autocompletion } from "@codemirror/autocomplete";
|
import { autocompletion } from "@codemirror/autocomplete";
|
||||||
import { abbreviationTracker, expandAbbreviation } from "@emmetio/codemirror6-plugin";
|
import { abbreviationTracker, expandAbbreviation } from "@emmetio/codemirror6-plugin";
|
||||||
|
import { HighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
||||||
|
import { tags } from "@lezer/highlight";
|
||||||
|
|
||||||
// Custom overrides for One Dark theme
|
// Custom theme with purple accent colors (matching app completed state)
|
||||||
|
const crispyTheme = EditorView.theme(
|
||||||
|
{
|
||||||
|
"&": {
|
||||||
|
backgroundColor: "#262630",
|
||||||
|
color: "#c8c8d0"
|
||||||
|
},
|
||||||
|
".cm-content": {
|
||||||
|
caretColor: "#9b6dd4"
|
||||||
|
},
|
||||||
|
".cm-cursor, .cm-dropCursor": {
|
||||||
|
borderLeftColor: "#9b6dd4"
|
||||||
|
},
|
||||||
|
"&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": {
|
||||||
|
backgroundColor: "#3e3e4a"
|
||||||
|
},
|
||||||
|
".cm-panels": {
|
||||||
|
backgroundColor: "#262630",
|
||||||
|
color: "#c8c8d0"
|
||||||
|
},
|
||||||
|
".cm-searchMatch": {
|
||||||
|
backgroundColor: "#3e3e4a",
|
||||||
|
outline: "1px solid #9b6dd4"
|
||||||
|
},
|
||||||
|
".cm-searchMatch.cm-searchMatch-selected": {
|
||||||
|
backgroundColor: "rgba(155, 109, 212, 0.3)"
|
||||||
|
},
|
||||||
|
".cm-activeLine": {
|
||||||
|
backgroundColor: "#2e2e3a"
|
||||||
|
},
|
||||||
|
".cm-selectionMatch": {
|
||||||
|
backgroundColor: "#3e3e4a"
|
||||||
|
},
|
||||||
|
".cm-gutters": {
|
||||||
|
backgroundColor: "#262630",
|
||||||
|
color: "#808090",
|
||||||
|
border: "none"
|
||||||
|
},
|
||||||
|
".cm-activeLineGutter": {
|
||||||
|
backgroundColor: "#2e2e3a"
|
||||||
|
},
|
||||||
|
".cm-lineNumbers .cm-gutterElement": {
|
||||||
|
color: "#808090"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ dark: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Syntax highlighting with purple accent
|
||||||
|
const crispyHighlight = HighlightStyle.define([
|
||||||
|
{ tag: tags.keyword, color: "#c9a6eb" },
|
||||||
|
{ tag: tags.operator, color: "#cdd6f4" },
|
||||||
|
{ tag: tags.variableName, color: "#89b4fa" },
|
||||||
|
{ tag: tags.propertyName, color: "#89b4fa" },
|
||||||
|
{ tag: tags.attributeName, color: "#89b4fa" },
|
||||||
|
{ tag: tags.className, color: "#89b4fa" },
|
||||||
|
{ tag: tags.tagName, color: "#c9a6eb" },
|
||||||
|
{ tag: tags.string, color: "#a6e3a1" },
|
||||||
|
{ tag: tags.number, color: "#fab387" },
|
||||||
|
{ tag: tags.bool, color: "#fab387" },
|
||||||
|
{ tag: tags.null, color: "#fab387" },
|
||||||
|
{ tag: tags.comment, color: "#6c7086", fontStyle: "italic" },
|
||||||
|
{ tag: tags.bracket, color: "#cdd6f4" },
|
||||||
|
{ tag: tags.punctuation, color: "#cdd6f4" },
|
||||||
|
{ tag: tags.definition(tags.variableName), color: "#89b4fa" },
|
||||||
|
{ tag: tags.function(tags.variableName), color: "#89b4fa" },
|
||||||
|
{ tag: tags.atom, color: "#c9a6eb" },
|
||||||
|
{ tag: tags.unit, color: "#a6e3a1" },
|
||||||
|
{ tag: tags.color, color: "#f9e2af" }
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Combined theme export
|
||||||
|
export const crispyEditorTheme = [crispyTheme, syntaxHighlighting(crispyHighlight)];
|
||||||
|
|
||||||
|
// Custom overrides for editor styling
|
||||||
const editorTheme = EditorView.theme(
|
const editorTheme = EditorView.theme(
|
||||||
{
|
{
|
||||||
"&": {
|
"&": {
|
||||||
@@ -51,7 +126,7 @@ export class CodeEditor {
|
|||||||
// Build extensions array
|
// Build extensions array
|
||||||
const extensions = [
|
const extensions = [
|
||||||
langExtension,
|
langExtension,
|
||||||
oneDark,
|
crispyEditorTheme,
|
||||||
editorTheme,
|
editorTheme,
|
||||||
// History for undo/redo
|
// History for undo/redo
|
||||||
history(),
|
history(),
|
||||||
|
|||||||
Reference in New Issue
Block a user