+
-
+
start with # end with a space
diff --git a/src/components/blog/TextEditor.tsx b/src/components/blog/TextEditor.tsx
index 3a89917..3e168ba 100644
--- a/src/components/blog/TextEditor.tsx
+++ b/src/components/blog/TextEditor.tsx
@@ -1,4 +1,4 @@
-import { Show, untrack, createEffect, on, createSignal } from "solid-js";
+import { Show, untrack, createEffect, on, createSignal, For } from "solid-js";
import { createTiptapEditor, useEditorHTML } from "solid-tiptap";
import StarterKit from "@tiptap/starter-kit";
import Link from "@tiptap/extension-link";
@@ -11,17 +11,95 @@ import js from "highlight.js/lib/languages/javascript";
import ts from "highlight.js/lib/languages/typescript";
import ocaml from "highlight.js/lib/languages/ocaml";
import rust from "highlight.js/lib/languages/rust";
+import python from "highlight.js/lib/languages/python";
+import java from "highlight.js/lib/languages/java";
+import go from "highlight.js/lib/languages/go";
+import c from "highlight.js/lib/languages/c";
+import cpp from "highlight.js/lib/languages/cpp";
+import csharp from "highlight.js/lib/languages/csharp";
+import sql from "highlight.js/lib/languages/sql";
+import bash from "highlight.js/lib/languages/bash";
+import json from "highlight.js/lib/languages/json";
+import yaml from "highlight.js/lib/languages/yaml";
+import markdown from "highlight.js/lib/languages/markdown";
+import xml from "highlight.js/lib/languages/xml";
+import php from "highlight.js/lib/languages/php";
+import ruby from "highlight.js/lib/languages/ruby";
+import swift from "highlight.js/lib/languages/swift";
+import kotlin from "highlight.js/lib/languages/kotlin";
+import dockerfile from "highlight.js/lib/languages/dockerfile";
// Create lowlight instance with common languages
const lowlight = createLowlight(common);
-// Register additional languages
+// Register existing languages
lowlight.register("css", css);
lowlight.register("js", js);
+lowlight.register("javascript", js);
lowlight.register("ts", ts);
+lowlight.register("typescript", ts);
lowlight.register("ocaml", ocaml);
lowlight.register("rust", rust);
+// Register new languages
+lowlight.register("python", python);
+lowlight.register("py", python);
+lowlight.register("java", java);
+lowlight.register("go", go);
+lowlight.register("golang", go);
+lowlight.register("c", c);
+lowlight.register("cpp", cpp);
+lowlight.register("c++", cpp);
+lowlight.register("csharp", csharp);
+lowlight.register("cs", csharp);
+lowlight.register("sql", sql);
+lowlight.register("bash", bash);
+lowlight.register("shell", bash);
+lowlight.register("sh", bash);
+lowlight.register("json", json);
+lowlight.register("yaml", yaml);
+lowlight.register("yml", yaml);
+lowlight.register("markdown", markdown);
+lowlight.register("md", markdown);
+lowlight.register("xml", xml);
+lowlight.register("html", xml);
+lowlight.register("php", php);
+lowlight.register("ruby", ruby);
+lowlight.register("rb", ruby);
+lowlight.register("swift", swift);
+lowlight.register("kotlin", kotlin);
+lowlight.register("kt", kotlin);
+lowlight.register("dockerfile", dockerfile);
+lowlight.register("docker", dockerfile);
+
+// Available languages for selector
+const AVAILABLE_LANGUAGES = [
+ { value: null, label: "Plain Text" },
+ { value: "bash", label: "Bash/Shell" },
+ { value: "c", label: "C" },
+ { value: "cpp", label: "C++" },
+ { value: "csharp", label: "C#" },
+ { value: "css", label: "CSS" },
+ { value: "dockerfile", label: "Dockerfile" },
+ { value: "go", label: "Go" },
+ { value: "html", label: "HTML" },
+ { value: "java", label: "Java" },
+ { value: "javascript", label: "JavaScript" },
+ { value: "json", label: "JSON" },
+ { value: "kotlin", label: "Kotlin" },
+ { value: "markdown", label: "Markdown" },
+ { value: "ocaml", label: "OCaml" },
+ { value: "php", label: "PHP" },
+ { value: "python", label: "Python" },
+ { value: "ruby", label: "Ruby" },
+ { value: "rust", label: "Rust" },
+ { value: "sql", label: "SQL" },
+ { value: "swift", label: "Swift" },
+ { value: "typescript", label: "TypeScript" },
+ { value: "xml", label: "XML" },
+ { value: "yaml", label: "YAML" }
+] as const;
+
// IFrame extension
interface IframeOptions {
allowFullscreen: boolean;
@@ -112,6 +190,12 @@ export default function TextEditor(props: TextEditorProps) {
left: 0
});
+ const [showLanguageSelector, setShowLanguageSelector] = createSignal(false);
+ const [languageSelectorPosition, setLanguageSelectorPosition] = createSignal({
+ top: 0,
+ left: 0
+ });
+
const editor = createTiptapEditor(() => ({
element: editorRef,
extensions: [
@@ -212,6 +296,50 @@ export default function TextEditor(props: TextEditorProps) {
}
};
+ const insertCodeBlock = (language: string | null) => {
+ const instance = editor();
+ if (!instance) return;
+
+ instance.chain().focus().toggleCodeBlock().run();
+
+ // If language specified, update the node attributes
+ if (language) {
+ instance.chain().updateAttributes("codeBlock", { language }).run();
+ }
+
+ setShowLanguageSelector(false);
+ };
+
+ const showLanguagePicker = (e: MouseEvent) => {
+ const buttonRect = (e.currentTarget as HTMLElement).getBoundingClientRect();
+ setLanguageSelectorPosition({
+ top: buttonRect.bottom + 5,
+ left: buttonRect.left
+ });
+ setShowLanguageSelector(!showLanguageSelector());
+ };
+
+ // Close language selector on outside click
+ createEffect(() => {
+ if (showLanguageSelector()) {
+ const handleClickOutside = (e: MouseEvent) => {
+ const target = e.target as HTMLElement;
+ if (
+ !target.closest(".language-selector") &&
+ !target.closest("[data-language-picker-trigger]")
+ ) {
+ setShowLanguageSelector(false);
+ }
+ };
+
+ setTimeout(() => {
+ document.addEventListener("click", handleClickOutside);
+ }, 0);
+
+ return () => document.removeEventListener("click", handleClickOutside);
+ }
+ });
+
return (
@@ -348,6 +476,29 @@ export default function TextEditor(props: TextEditorProps) {
+ {/* Language Selector Dropdown */}
+
+
+
+ {(lang) => (
+
+ )}
+
+
+
+