From c124311880c0b7d0dba9407bdfa6d154d37e0c03 Mon Sep 17 00:00:00 2001
From: Seviche <me@seviche.cc>
Date: Thu, 30 Mar 2023 21:50:29 +0800
Subject: [PATCH] feat: add codeblock command

---
 package.json                           |   3 +-
 pnpm-lock.yaml                         |  52 +++-
 src/assets/hljs/nord.css               | 342 +++++++++++++++++++++++++
 src/assets/hljs/tokyo-night-dark.css   | 117 +++++++++
 src/assets/hljs/tokyo-night-light.css  | 117 +++++++++
 src/{ => assets}/style.css             |   4 +-
 src/components/Tiptap/CommandsList.vue |   2 +
 src/components/Tiptap/Editor.vue       |  49 +++-
 src/components/Tiptap/commands.js      |   2 +
 src/components/Tiptap/suggestion.js    |  27 +-
 src/main.ts                            |   2 +-
 11 files changed, 697 insertions(+), 20 deletions(-)
 create mode 100644 src/assets/hljs/nord.css
 create mode 100644 src/assets/hljs/tokyo-night-dark.css
 create mode 100644 src/assets/hljs/tokyo-night-light.css
 rename src/{ => assets}/style.css (92%)

diff --git a/package.json b/package.json
index 6578db9..977ec32 100644
--- a/package.json
+++ b/package.json
@@ -17,7 +17,7 @@
     "@tiptap/core": "2.0.0-beta.220",
     "@tiptap/extension-bubble-menu": "2.0.0-beta.220",
     "@tiptap/extension-character-count": "2.0.0-beta.220",
-    "@tiptap/extension-code-block": "^2.0.0",
+    "@tiptap/extension-code-block-lowlight": "^2.0.1",
     "@tiptap/extension-highlight": "^2.0.0",
     "@tiptap/extension-link": "2.0.0-beta.220",
     "@tiptap/extension-typography": "2.0.0-beta.220",
@@ -26,6 +26,7 @@
     "@tiptap/suggestion": "^2.0.0",
     "@tiptap/vue-3": "2.0.0-beta.220",
     "install": "^0.13.0",
+    "lowlight": "^2.8.1",
     "masto": "^5.10.0",
     "tippy.js": "^6.3.7",
     "vue": "^3.2.47"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a944638..d9c3dda 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -19,9 +19,9 @@ dependencies:
   '@tiptap/extension-character-count':
     specifier: 2.0.0-beta.220
     version: 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220)
-  '@tiptap/extension-code-block':
-    specifier: ^2.0.0
-    version: 2.0.0(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220)
+  '@tiptap/extension-code-block-lowlight':
+    specifier: ^2.0.1
+    version: 2.0.1(@tiptap/core@2.0.0-beta.220)(@tiptap/extension-code-block@2.0.0)(@tiptap/pm@2.0.0-beta.220)
   '@tiptap/extension-highlight':
     specifier: ^2.0.0
     version: 2.0.0(@tiptap/core@2.0.0-beta.220)
@@ -46,6 +46,9 @@ dependencies:
   install:
     specifier: ^0.13.0
     version: 0.13.0
+  lowlight:
+    specifier: ^2.8.1
+    version: 2.8.1
   masto:
     specifier: ^5.10.0
     version: 5.10.0
@@ -706,6 +709,18 @@ packages:
       '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)
     dev: false
 
+  /@tiptap/extension-code-block-lowlight@2.0.1(@tiptap/core@2.0.0-beta.220)(@tiptap/extension-code-block@2.0.0)(@tiptap/pm@2.0.0-beta.220):
+    resolution: {integrity: sha512-AUEeOfHSYh9a7+Lv57LSnYOJkC1lUhQC3AtjJK/1LG8NzDuL1XY+wpP0WKLKsH2qr95bJNi26amIcdVGtIVupg==}
+    peerDependencies:
+      '@tiptap/core': ^2.0.0
+      '@tiptap/extension-code-block': ^2.0.0
+      '@tiptap/pm': ^2.0.0
+    dependencies:
+      '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220)
+      '@tiptap/extension-code-block': 2.0.0(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220)
+      '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)
+    dev: false
+
   /@tiptap/extension-code-block@2.0.0(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220):
     resolution: {integrity: sha512-rkI2W8037A9BWtsYNhuzA4/IjJF1jafmGGXKh56xLW7hkW563u33jizvQ+f+g+5dofKWUd+0coMv0bDax7ANCg==}
     peerDependencies:
@@ -950,6 +965,12 @@ packages:
       vue: 3.2.47
     dev: false
 
+  /@types/hast@2.3.4:
+    resolution: {integrity: sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==}
+    dependencies:
+      '@types/unist': 2.0.6
+    dev: false
+
   /@types/json-schema@7.0.11:
     resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
     dev: true
@@ -997,7 +1018,6 @@ packages:
 
   /@types/unist@2.0.6:
     resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==}
-    dev: true
 
   /@typescript-eslint/eslint-plugin@5.56.0(@typescript-eslint/parser@5.56.0)(eslint@8.36.0)(typescript@5.0.2):
     resolution: {integrity: sha512-ZNW37Ccl3oMZkzxrYDUX4o7cnuPgU+YrcaYXzsRtLB16I1FR5SHMqga3zGsaSliZADCWo2v8qHWqAYIj8nWCCg==}
@@ -2435,6 +2455,12 @@ packages:
     dependencies:
       reusify: 1.0.4
 
+  /fault@2.0.1:
+    resolution: {integrity: sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==}
+    dependencies:
+      format: 0.2.2
+    dev: false
+
   /file-entry-cache@6.0.1:
     resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
     engines: {node: ^10.12.0 || >=12.0.0}
@@ -2499,6 +2525,11 @@ packages:
       mime-types: 2.1.35
     dev: false
 
+  /format@0.2.2:
+    resolution: {integrity: sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=}
+    engines: {node: '>=0.4.x'}
+    dev: false
+
   /fraction.js@4.2.0:
     resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
     dev: true
@@ -2672,6 +2703,11 @@ packages:
       tslib: 2.5.0
     dev: false
 
+  /highlight.js@11.7.0:
+    resolution: {integrity: sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ==}
+    engines: {node: '>=12.0.0'}
+    dev: false
+
   /hosted-git-info@2.8.9:
     resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
     dev: true
@@ -3134,6 +3170,14 @@ packages:
       tslib: 2.5.0
     dev: false
 
+  /lowlight@2.8.1:
+    resolution: {integrity: sha512-HCaGL61RKc1MYzEYn3rFoGkK0yslzCVDFJEanR19rc2L0mb8i58XM55jSRbzp9jcQrFzschPlwooC0vuNitk8Q==}
+    dependencies:
+      '@types/hast': 2.3.4
+      fault: 2.0.1
+      highlight.js: 11.7.0
+    dev: false
+
   /lru-cache@6.0.0:
     resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
     engines: {node: '>=10'}
diff --git a/src/assets/hljs/nord.css b/src/assets/hljs/nord.css
new file mode 100644
index 0000000..c186709
--- /dev/null
+++ b/src/assets/hljs/nord.css
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2017-present Arctic Ice Studio <development@arcticicestudio.com>
+ * Copyright (c) 2017-present Sven Greb <development@svengreb.de>
+ *
+ * Project:    Nord highlight.js
+ * Version:    0.1.0
+ * Repository: https://github.com/arcticicestudio/nord-highlightjs
+ * License:    MIT
+ * References:
+ *   https://github.com/arcticicestudio/nord
+ */
+
+/*
+
+Polar Night
+
+#2E3440
+#3B4252
+#434C5E
+#4C566A
+
+Snow Storm
+
+#D8DEE9
+#E5E9F0
+#ECEFF4
+
+Frost
+
+#8FBCBB
+#88C0D0
+#81A1C1
+#5E81AC
+
+Aurora
+
+#BF616A
+#D08770
+#EBCB8B
+#A3BE8C
+#B48EAD
+
+*/
+
+.hljs {
+  background: #2E3440;
+}
+
+.hljs,
+.hljs-subst {
+  color: #D8DEE9;
+}
+
+.hljs-selector-tag {
+  color: #81A1C1;
+}
+
+.hljs-selector-id {
+  color: #8FBCBB;
+  font-weight: bold;
+}
+
+.hljs-selector-class {
+  color: #8FBCBB;
+}
+
+.hljs-selector-attr {
+  color: #8FBCBB;
+}
+
+.hljs-property {
+  color: #88C0D0;
+}
+
+.hljs-selector-pseudo {
+  color: #88C0D0;
+}
+
+.hljs-addition {
+  background-color: rgba(163, 190, 140, 0.5);
+}
+
+.hljs-deletion {
+  background-color: rgba(191, 97, 106, 0.5);
+}
+
+.hljs-built_in,
+.hljs-type {
+  color: #8FBCBB;
+}
+
+.hljs-class {
+  color: #8FBCBB;
+}
+
+.hljs-function {
+  color: #88C0D0;
+}
+
+.hljs-title.hljs-function,
+.hljs-function > .hljs-title {
+  color: #88C0D0;
+}
+
+.hljs-keyword,
+.hljs-literal,
+.hljs-symbol {
+  color: #81A1C1;
+}
+
+.hljs-number {
+  color: #B48EAD;
+}
+
+.hljs-regexp {
+  color: #EBCB8B;
+}
+
+.hljs-string {
+  color: #A3BE8C;
+}
+
+.hljs-title {
+  color: #8FBCBB;
+}
+
+.hljs-params {
+  color: #D8DEE9;
+}
+
+.hljs-bullet {
+  color: #81A1C1;
+}
+
+.hljs-code {
+  color: #8FBCBB;
+}
+
+.hljs-emphasis {
+  font-style: italic;
+}
+
+.hljs-formula {
+  color: #8FBCBB;
+}
+
+.hljs-strong {
+  font-weight: bold;
+}
+
+.hljs-link:hover {
+  text-decoration: underline;
+}
+
+.hljs-quote {
+  color: #4C566A;
+}
+
+.hljs-comment {
+  color: #4C566A;
+}
+
+.hljs-doctag {
+  color: #8FBCBB;
+}
+
+.hljs-meta,
+.hljs-meta .hljs-keyword {
+
+  color: #5E81AC;
+}
+
+.hljs-meta .hljs-string {
+  color: #A3BE8C;
+}
+
+.hljs-attr {
+  color: #8FBCBB;
+}
+
+.hljs-attribute {
+  color: #D8DEE9;
+}
+
+.hljs-name {
+  color: #81A1C1;
+}
+
+.hljs-section {
+  color: #88C0D0;
+}
+
+.hljs-tag {
+  color: #81A1C1;
+}
+
+.hljs-variable {
+  color: #D8DEE9;
+}
+
+.hljs-template-variable {
+  color: #D8DEE9;
+}
+
+.hljs-template-tag {
+  color: #5E81AC;
+}
+
+/* per language customizations */
+
+.language-abnf .hljs-attribute {
+  color: #88C0D0;
+}
+
+.language-abnf .hljs-symbol {
+  color: #EBCB8B;
+}
+
+.language-apache .hljs-attribute {
+  color: #88C0D0;
+}
+
+.language-apache .hljs-section {
+  color: #81A1C1;
+}
+
+.language-arduino .hljs-built_in {
+  color: #88C0D0;
+}
+
+.language-aspectj .hljs-meta {
+  color: #D08770;
+}
+
+.language-aspectj > .hljs-title {
+  color: #88C0D0;
+}
+
+.language-bnf .hljs-attribute {
+  color: #8FBCBB;
+}
+
+.language-clojure .hljs-name {
+  color: #88C0D0;
+}
+
+.language-clojure .hljs-symbol {
+  color: #EBCB8B;
+}
+
+.language-coq .hljs-built_in {
+  color: #88C0D0;
+}
+
+.language-cpp .hljs-meta .hljs-string {
+  color: #8FBCBB;
+}
+
+.language-css .hljs-built_in {
+  color: #88C0D0;
+}
+
+.language-css .hljs-keyword {
+  color: #D08770;
+}
+
+.language-diff .hljs-meta {
+  color: #8FBCBB;
+}
+
+.language-ebnf .hljs-attribute {
+  color: #8FBCBB;
+}
+
+.language-glsl .hljs-built_in {
+  color: #88C0D0;
+}
+
+.language-groovy .hljs-meta:not(:first-child) {
+  color: #D08770;
+}
+
+.language-haxe .hljs-meta {
+  color: #D08770;
+}
+
+.language-java .hljs-meta {
+  color: #D08770;
+}
+
+.language-ldif .hljs-attribute {
+  color: #8FBCBB;
+}
+
+.language-lisp .hljs-name {
+  color: #88C0D0;
+}
+
+.language-lua .hljs-built_in {
+  color: #88C0D0;
+}
+
+.language-moonscript .hljs-built_in {
+  color: #88C0D0;
+}
+
+.language-nginx .hljs-attribute {
+  color: #88C0D0;
+}
+
+.language-nginx .hljs-section {
+  color: #5E81AC;
+}
+
+.language-pf .hljs-built_in {
+  color: #88C0D0;
+}
+
+.language-processing .hljs-built_in {
+  color: #88C0D0;
+}
+
+.language-scss .hljs-keyword {
+  color: #81A1C1;
+}
+
+.language-stylus .hljs-keyword {
+  color: #81A1C1;
+}
+
+.language-swift .hljs-meta {
+  color: #D08770;
+}
+
+.language-vim .hljs-built_in {
+  color: #88C0D0;
+  font-style: italic;
+}
+
+.language-yaml .hljs-meta {
+  color: #D08770;
+}
\ No newline at end of file
diff --git a/src/assets/hljs/tokyo-night-dark.css b/src/assets/hljs/tokyo-night-dark.css
new file mode 100644
index 0000000..c442a85
--- /dev/null
+++ b/src/assets/hljs/tokyo-night-dark.css
@@ -0,0 +1,117 @@
+/*!
+  Theme: Tokyo-night-Dark
+  origin: https://github.com/enkia/tokyo-night-vscode-theme
+  Description: Original highlight.js style
+  Author: (c) Henri Vandersleyen <hvandersleyen@gmail.com>
+  License: see project LICENSE
+  Touched: 2022
+*/
+
+/*  Comment */
+.hljs-meta,
+.hljs-comment {
+  color: #565f89;
+}
+
+/* Red */
+/*INFO: This keyword, HTML elements, Regex group symbol, CSS units, Terminal Red */
+.hljs-tag,
+.hljs-doctag,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-regexp,
+.hljs-template-tag,
+.hljs-selector-pseudo,
+.hljs-selector-attr,
+.hljs-variable.language_,
+.hljs-deletion {
+  color: #f7768e;
+}
+
+/*Orange */
+/*INFO: Number and Boolean constants, Language support constants */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-number,
+.hljs-literal,
+.hljs-type,
+.hljs-params,
+.hljs-link {
+  color: #ff9e64;
+}
+
+
+/*  Yellow */
+/* INFO:  	Function parameters, Regex character sets, Terminal Yellow */
+.hljs-built_in, 
+.hljs-attribute {
+  color: #e0af68;
+}
+/* cyan */
+/* INFO: Language support functions, CSS HTML elements */
+.hljs-selector-tag {
+  color: #2ac3de;
+}
+
+/* light blue */
+/* INFO: Object properties, Regex quantifiers and flags, Markdown headings, Terminal Cyan, Markdown code, Import/export keywords */
+.hljs-keyword,
+  .hljs-title.function_,
+.hljs-title,
+.hljs-title.class_,
+.hljs-title.class_.inherited__,
+.hljs-subst,
+.hljs-property {color: #7dcfff;}
+
+/*Green*/
+/* INFO: Object literal keys, Markdown links, Terminal Green */
+.hljs-selector-tag { color: #73daca;}
+
+
+/*Green(er) */
+/* INFO: Strings, CSS class names */
+.hljs-quote,
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition {
+  color: #9ece6a;
+}
+
+/* Blue */
+/* INFO:  	Function names, CSS property names, Terminal Blue */
+.hljs-code,
+.hljs-formula,
+.hljs-section {
+  color: #7aa2f7;
+}
+
+
+
+/* Magenta */
+/*INFO: Control Keywords, Storage Types, Regex symbols and operators, HTML Attributes, Terminal Magenta */
+.hljs-name,
+.hljs-keyword,
+.hljs-operator,
+.hljs-keyword,
+.hljs-char.escape_,
+.hljs-attr {
+  color: #bb9af7;
+}
+
+/* white*/
+/* INFO: Variables, Class names, Terminal White */
+.hljs-punctuation {color: #c0caf5}
+
+.hljs {
+  background: #1a1b26;
+  color: #9aa5ce;
+}
+
+.hljs-emphasis {
+  font-style: italic;
+}
+
+.hljs-strong {
+  font-weight: bold;
+}
\ No newline at end of file
diff --git a/src/assets/hljs/tokyo-night-light.css b/src/assets/hljs/tokyo-night-light.css
new file mode 100644
index 0000000..dfdf157
--- /dev/null
+++ b/src/assets/hljs/tokyo-night-light.css
@@ -0,0 +1,117 @@
+/*!
+  Theme: Tokyo-night-light
+  origin: https://github.com/enkia/tokyo-night-vscode-theme
+  Description: Original highlight.js style
+  Author: (c) Henri Vandersleyen <hvandersleyen@gmail.com>
+  License: see project LICENSE
+  Touched: 2022
+*/
+
+/*  Comment */
+.hljs-meta,
+.hljs-comment {
+  color: #9699a3;
+}
+
+/* Red */
+/*INFO: This keyword, HTML elements, Regex group symbol, CSS units, Terminal Red */
+.hljs-tag,
+.hljs-doctag,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-regexp,
+.hljs-template-tag,
+.hljs-selector-pseudo,
+.hljs-selector-attr,
+.hljs-variable.language_,
+.hljs-deletion {
+  color: #8c4351;
+}
+
+/*Orange */
+/*INFO: Number and Boolean constants, Language support constants */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-number,
+.hljs-literal,
+.hljs-type,
+.hljs-params,
+.hljs-link {
+  color: #965027;
+}
+
+
+/*  Yellow */
+/* INFO:  	Function parameters, Regex character sets, Terminal Yellow */
+.hljs-built_in, 
+.hljs-attribute {
+  color: #8f5e15;
+}
+/* cyan */
+/* INFO: Language support functions, CSS HTML elements */
+.hljs-selector-tag {
+  color: #166775;
+}
+
+/* light blue */
+/* INFO: Object properties, Regex quantifiers and flags, Markdown headings, Terminal Cyan, Markdown code, Import/export keywords */
+.hljs-keyword,
+  .hljs-title.function_,
+.hljs-title,
+.hljs-title.class_,
+.hljs-title.class_.inherited__,
+.hljs-subst,
+.hljs-property {color: #0f4b6e;}
+
+/*Green*/
+/* INFO: Object literal keys, Markdown links, Terminal Green */
+.hljs-selector-tag { color: #33635c;}
+
+
+/*Green(er) */
+/* INFO: Strings, CSS class names */
+.hljs-quote,
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition {
+  color: #485e30;
+}
+
+/* Blue */
+/* INFO:  	Function names, CSS property names, Terminal Blue */
+.hljs-code,
+.hljs-formula,
+.hljs-section {
+  color: #34548a;
+}
+
+
+
+/* Magenta */
+/*INFO: Control Keywords, Storage Types, Regex symbols and operators, HTML Attributes, Terminal Magenta */
+.hljs-name,
+.hljs-keyword,
+.hljs-operator,
+.hljs-keyword,
+.hljs-char.escape_,
+.hljs-attr {
+  color: #5a4a78;
+}
+
+/* white*/
+/* INFO: Variables, Class names, Terminal White */
+.hljs-punctuation {color: #343b58}
+
+.hljs {
+  background: #d5d6db;
+  color: #565a6e;
+}
+
+.hljs-emphasis {
+  font-style: italic;
+}
+
+.hljs-strong {
+  font-weight: bold;
+}
diff --git a/src/style.css b/src/assets/style.css
similarity index 92%
rename from src/style.css
rename to src/assets/style.css
index 10c35c6..18004cd 100644
--- a/src/style.css
+++ b/src/assets/style.css
@@ -1,3 +1,5 @@
+@import url("./hljs/nord.css");
+
 @tailwind base;
 @tailwind components;
 @tailwind utilities;
@@ -33,4 +35,4 @@
 
 a {
   color: #68CEF8;
-}
\ No newline at end of file
+}
diff --git a/src/components/Tiptap/CommandsList.vue b/src/components/Tiptap/CommandsList.vue
index f0df2ca..ed34430 100644
--- a/src/components/Tiptap/CommandsList.vue
+++ b/src/components/Tiptap/CommandsList.vue
@@ -1,4 +1,6 @@
 <script>
+// ⚠️ Experiment
+// Ref: https://tiptap.dev/experiments/commands
 export default {
   props: {
     items: {
diff --git a/src/components/Tiptap/Editor.vue b/src/components/Tiptap/Editor.vue
index 2124b51..e2d1c3c 100644
--- a/src/components/Tiptap/Editor.vue
+++ b/src/components/Tiptap/Editor.vue
@@ -4,16 +4,53 @@ import StarterKit from '@tiptap/starter-kit'
 import Typography from '@tiptap/extension-typography'
 import Link from '@tiptap/extension-link'
 import Highlight from '@tiptap/extension-highlight'
+import { lowlight } from 'lowlight/lib/core'
+import CodeBlockLowlight from '@tiptap/extension-code-block-lowlight'
+import html from 'highlight.js/lib/languages/xml'
+import css from 'highlight.js/lib/languages/css'
+import js from 'highlight.js/lib/languages/javascript'
+import ts from 'highlight.js/lib/languages/typescript'
+import python from 'highlight.js/lib/languages/python'
+import c from 'highlight.js/lib/languages/c'
+import cpp from 'highlight.js/lib/languages/cpp'
+import bash from 'highlight.js/lib/languages/bash'
+import scss from 'highlight.js/lib/languages/scss'
+import go from 'highlight.js/lib/languages/go'
+import rust from 'highlight.js/lib/languages/rust'
+
 import suggestion from './suggestion'
 import BubbleMenu from './BubbleMenu.vue'
 import Commands from './commands'
 
+lowlight.registerLanguage('html', html)
+lowlight.registerLanguage('css', css)
+lowlight.registerLanguage('js', js)
+lowlight.registerLanguage('ts', ts)
+lowlight.registerLanguage('py', python)
+lowlight.registerLanguage('c', c)
+lowlight.registerLanguage('cpp', cpp)
+lowlight.registerLanguage('bash', bash)
+lowlight.registerLanguage('scss', scss)
+lowlight.registerLanguage('go', go)
+lowlight.registerLanguage('rs', rust)
+
 const editor = useEditor({
   content: `<p>
-          Wow, this editor has support for links to the whole <a href="https://en.wikipedia.org/wiki/World_Wide_Web">world wide web</a>. We tested a lot of URLs and I think you can add *every URL* you want. Isn’t that cool? Let’s try <a href="https://statamic.com/">another one!</a> Yep, seems to work.
+          That’s a boring paragraph followed by a fenced code block:
         </p>
+        <pre><code>for (var i=1; i <= 20; i++)
+{
+  if (i % 15 == 0)
+    console.log("FizzBuzz");
+  else if (i % 3 == 0)
+    console.log("Fizz");
+  else if (i % 5 == 0)
+    console.log("Buzz");
+  else
+    console.log(i);
+}</code></pre>
         <p>
-          By default every link will get a <code>rel="noopener noreferrer nofollow"</code> attribute. It’s configurable though.
+          Press Command/Ctrl + Enter to leave the fenced code block and continue typing in boring paragraphs.
         </p>`,
   extensions: [
     StarterKit,
@@ -29,12 +66,18 @@ const editor = useEditor({
         class: 'bg-blue-100',
       },
     }),
+    CodeBlockLowlight.configure({
+      lowlight,
+      HTMLAttributes: {
+        class: 'not-prose hljs',
+      },
+    }),
   ],
   editable: true,
   autofocus: true,
   editorProps: {
     attributes: {
-      class: 'prose',
+      class: 'prose prose-slate mx-auto',
     },
   },
 })
diff --git a/src/components/Tiptap/commands.js b/src/components/Tiptap/commands.js
index ea3f57f..034a4a5 100644
--- a/src/components/Tiptap/commands.js
+++ b/src/components/Tiptap/commands.js
@@ -1,3 +1,5 @@
+// ⚠️ Experiment
+// Ref: https://tiptap.dev/experiments/commands
 import { Extension } from '@tiptap/core'
 import Suggestion from '@tiptap/suggestion'
 
diff --git a/src/components/Tiptap/suggestion.js b/src/components/Tiptap/suggestion.js
index ee6f3ec..5b47f06 100644
--- a/src/components/Tiptap/suggestion.js
+++ b/src/components/Tiptap/suggestion.js
@@ -1,3 +1,5 @@
+// ⚠️ Experiment
+// Ref: https://tiptap.dev/experiments/commands
 import { VueRenderer } from '@tiptap/vue-3'
 import tippy from 'tippy.js'
 
@@ -29,28 +31,33 @@ export default {
         },
       },
       {
-        title: 'code block',
+        title: 'H3',
         command: ({ editor, range }) => {
           editor
             .chain()
             .focus()
             .deleteRange(range)
-            .setNode('pre')
+            .setNode('heading', { level: 3 })
             .run()
         },
       },
       {
-        title: 'italic',
+        title: 'Code block',
         command: ({ editor, range }) => {
-          editor
-            .chain()
-            .focus()
-            .deleteRange(range)
-            .setMark('italic')
-            .run()
+          editor.chain().focus().deleteRange(range).setCodeBlock().run()
         },
       },
-    ].filter(item => item.title.toLowerCase().startsWith(query.toLowerCase())).slice(0, 10)
+      {
+        title: 'Bullet List',
+        command: ({ editor, range }) => {
+          editor.chain().focus().deleteRange(range).setMark('italic').run()
+        },
+      },
+    ]
+      .filter(item =>
+        item.title.toLowerCase().startsWith(query.toLowerCase()),
+      )
+      .slice(0, 10)
   },
 
   render: () => {
diff --git a/src/main.ts b/src/main.ts
index 499b10e..3b78474 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,5 +1,5 @@
 import { createApp } from 'vue'
-import './style.css'
+import './assets/style.css'
 import App from './App.vue'
 
 const app = createApp(App)