feat: add codeblock command

This commit is contained in:
Seviche CC 2023-03-30 21:50:29 +08:00
parent dd11ef1efe
commit c124311880
Signed by: SevicheCC
GPG key ID: C577000000000000
11 changed files with 697 additions and 20 deletions

View file

@ -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"

View file

@ -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'}

342
src/assets/hljs/nord.css Normal file
View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -1,3 +1,5 @@
@import url("./hljs/nord.css");
@tailwind base;
@tailwind components;
@tailwind utilities;
@ -33,4 +35,4 @@
a {
color: #68CEF8;
}
}

View file

@ -1,4 +1,6 @@
<script>
// Experiment
// Ref: https://tiptap.dev/experiments/commands
export default {
props: {
items: {

View file

@ -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. Isnt that cool? Lets try <a href="https://statamic.com/">another one!</a> Yep, seems to work.
Thats 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. Its 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',
},
},
})

View file

@ -1,3 +1,5 @@
// ⚠️ Experiment
// Ref: https://tiptap.dev/experiments/commands
import { Extension } from '@tiptap/core'
import Suggestion from '@tiptap/suggestion'

View file

@ -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: () => {

View file

@ -1,5 +1,5 @@
import { createApp } from 'vue'
import './style.css'
import './assets/style.css'
import App from './App.vue'
const app = createApp(App)