feat: code highlight

This commit is contained in:
KUN1007 2023-09-05 01:56:38 +08:00
parent f346249685
commit f94893c201
11 changed files with 268 additions and 33 deletions

View file

@ -26,6 +26,7 @@
"non-moe",
"persistedstate",
"Pinia",
"prismjs",
"rdquo",
"shinnku",
"signin",

View file

@ -25,6 +25,7 @@
"dompurify": "^3.0.5",
"pinia": "^2.1.6",
"pinia-plugin-persistedstate": "^3.2.0",
"prismjs": "^1.29.0",
"vue": "^3.3.4",
"vue-i18n": "^9.2.2",
"vue-router": "^4.2.4"
@ -33,6 +34,7 @@
"@iconify/vue": "^4.1.1",
"@types/dompurify": "^3.0.2",
"@types/node": "^20.4.8",
"@types/prismjs": "^1.26.0",
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.2",
"cross-env": "^7.0.3",
@ -41,6 +43,7 @@
"typescript": "^5.1.6",
"vite": "^4.4.8",
"vite-plugin-mock": "^3.0.0",
"vite-plugin-prismjs": "^0.0.8",
"vue-tsc": "^1.8.8"
},
"keywords": [

View file

@ -26,6 +26,9 @@ dependencies:
pinia-plugin-persistedstate:
specifier: ^3.2.0
version: 3.2.0(pinia@2.1.6)
prismjs:
specifier: ^1.29.0
version: 1.29.0
vue:
specifier: ^3.3.4
version: 3.3.4
@ -46,6 +49,9 @@ devDependencies:
'@types/node':
specifier: ^20.4.8
version: 20.4.8
'@types/prismjs':
specifier: ^1.26.0
version: 1.26.0
'@vitejs/plugin-vue':
specifier: ^4.2.3
version: 4.2.3(vite@4.4.8)(vue@3.3.4)
@ -70,6 +76,9 @@ devDependencies:
vite-plugin-mock:
specifier: ^3.0.0
version: 3.0.0(esbuild@0.18.19)(mockjs@1.1.0)(vite@4.4.8)
vite-plugin-prismjs:
specifier: ^0.0.8
version: 0.0.8(prismjs@1.29.0)
vue-tsc:
specifier: ^1.8.8
version: 1.8.8(typescript@5.1.6)
@ -712,6 +721,10 @@ packages:
resolution: {integrity: sha512-0mHckf6D2DiIAzh8fM8f3HQCvMKDpK94YQ0DSVkfWTG9BZleYIWudw9cJxX8oCk9bM+vAkDyujDV6dmKHbvQpg==}
dev: true
/@types/prismjs@1.26.0:
resolution: {integrity: sha512-ZTaqn/qSqUuAq1YwvOFQfVW1AR/oQJlLSZVustdjwI+GZ8kr0MSHBj0tsXPW1EqHubx50gtBEjbPGsdZwQwCjQ==}
dev: true
/@types/trusted-types@2.0.3:
resolution: {integrity: sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==}
dev: true
@ -1147,6 +1160,14 @@ packages:
picomatch: 2.3.1
dev: true
/babel-plugin-prismjs@2.1.0(prismjs@1.29.0):
resolution: {integrity: sha512-ehzSKYfeAz4U78zi/sfwsjDPlq0LvDKxNefcZTJ/iKBu+plsHsLqZhUeGf1+82LAcA35UZGbU6ksEx2Utphc/g==}
peerDependencies:
prismjs: ^1.18.0
dependencies:
prismjs: 1.29.0
dev: true
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
@ -1828,7 +1849,6 @@ packages:
/prismjs@1.29.0:
resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==}
engines: {node: '>=6'}
dev: false
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@ -2069,6 +2089,17 @@ packages:
- supports-color
dev: true
/vite-plugin-prismjs@0.0.8(prismjs@1.29.0):
resolution: {integrity: sha512-mBPPMS/hwVUArdqCtp/oajZT7iq1qwJDDCciNZ3R5+Q5tQUuUHXtDKuZHYnklPLElNbENf2FyuOtC4FrgxQRAA==}
engines: {node: '>=12.0.0'}
dependencies:
'@babel/core': 7.22.10
babel-plugin-prismjs: 2.1.0(prismjs@1.29.0)
transitivePeerDependencies:
- prismjs
- supports-color
dev: true
/vite@4.4.8(@types/node@20.4.8)(sass@1.64.2):
resolution: {integrity: sha512-LONawOUUjxQridNWGQlNizfKH89qPigK36XhMI7COMGztz8KNY0JHim7/xDd71CZwGT4HtSRgI7Hy+RlhG0Gvg==}
engines: {node: ^14.18.0 || >=16.0.0}

View file

@ -84,7 +84,7 @@ const handleRefreshPage = () => location.reload()
padding: 10px;
z-index: 1009;
position: absolute;
bottom: 50px;
top: 470px;
background-color: var(--kungalgame-white);
border: 1px solid var(--kungalgame-blue-1);
box-shadow: var(--shadow);

View file

@ -177,7 +177,6 @@ const handleChange = (editor: IDomEditor) => {
width: 100%;
margin: 0 auto;
z-index: 1008;
background-color: var(--kungalgame-trans-white-2);
}
.toolbar {

View file

@ -22,24 +22,11 @@ u {
text-decoration: underline;
}
/* 设置为 none不然黑夜模式代码块会花屏 */
* {
text-shadow: none;
}
/* 不显示分割线 */
.w-e-bar-divider {
display: none;
}
a {
color: var(--kungalgame-blue-5);
border-bottom: 1.5px solid var(--kungalgame-trans-white-9);
&:hover {
border-bottom: 1.5px solid var(--kungalgame-blue-5);
}
}
:root {
/* textarea - css vars */
--w-e-textarea-bg-color: var(--kungalgame-white-9);

View file

@ -0,0 +1,71 @@
/**
* 这是渲染 wangEditor 输出的富文本的样式
* 需要注意的是.kungalgame-topic-content 这个类名被全局注册了
*/
.kungalgame-topic-content {
border-radius: 5px;
padding: 0 10px;
margin-top: 20px;
overflow-x: auto;
* {
max-width: 100%;
overflow-y: scroll;
}
a {
color: var(--kungalgame-blue-5);
border-bottom: 1.5px solid var(--kungalgame-trans-white-9);
&:hover {
border-bottom: 1.5px solid var(--kungalgame-blue-5);
}
}
span {
text-shadow: none;
}
}
.kungalgame-topic-content p,
.kungalgame-topic-content li {
white-space: pre-wrap; /* 保留空格 */
}
.kungalgame-topic-content blockquote {
border-left: 8px solid var(--kungalgame-blue-1);
padding: 10px 10px;
margin: 10px 0;
background-color: var(--kungalgame-trans-blue-0);
}
.kungalgame-topic-content code {
font-family: monospace;
background-color: var(--kungalgame-trans-blue-0);
padding: 3px;
border-radius: 3px;
}
.kungalgame-topic-content pre > code {
display: block;
padding: 10px;
}
.kungalgame-topic-content table {
border-collapse: collapse;
}
.kungalgame-topic-content td,
.kungalgame-topic-content th {
border: 1px solid var(--kungalgame-blue-4);
min-width: 50px;
height: 20px;
}
.kungalgame-topic-content th {
background-color: var(--kungalgame-trans-blue-0);
}
.kungalgame-topic-content ul,
.kungalgame-topic-content ol {
padding-left: 20px;
}
.kungalgame-topic-content input[type='checkbox'] {
margin-right: 5px;
}

View file

@ -50,7 +50,7 @@ import KUNGalgameFooter from '@/components/KUNGalgameFooter.vue'
margin: 0 auto;
/* 容器的阴影 */
box-shadow: var(--shadow);
background-color: var(--kungalgame-trans-white-5);
background-color: var(--kungalgame-trans-white-2);
color: var(--kungalgame-font-color-3);
border: 1px solid var(--kungalgame-blue-1);
}
@ -62,8 +62,6 @@ import KUNGalgameFooter from '@/components/KUNGalgameFooter.vue'
display: flex;
flex-direction: column;
align-items: center;
background-color: var(--kungalgame-trans-white-5);
backdrop-filter: blur(5px);
}
@media (max-width: 1000px) {

View file

@ -32,6 +32,7 @@ const checkPublish = (topicData: EditCreateTopicRequestData) => {
message('Title cannot be empty!', '标题不可为空!', 'warn')
return false
} else if (topicData.content.trim()) {
// TODO:
console.log(getPlainText(topicData.content.trim()).length)
return true
} else {

View file

@ -1,47 +1,159 @@
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { onMounted, ref } from 'vue'
import prismjs from 'prismjs'
import 'prismjs/themes/prism.css'
import '@wangeditor/editor/dist/css/style.css'
import '@/styles/editor/editor.scss'
const width = ref('')
const html = ref<HTMLInputElement | null>(null)
defineProps<{
content: string
}>()
onMounted(() => {
width.value = computed(() => {
return 100 + '%'
}).value
//
prismjs.highlightAll()
})
</script>
<template>
<!-- 内容区右侧的话题展示区这里富文本必须用 v-html已经确定文本经过三次处理 -->
<!-- 这里用的 v-html样式是页面刷新后才会有的所以必须动态绑定样式 -->
<div class="w-e-text-container">
<div v-html="content" data-slate-editor></div>
<div class="kungalgame-topic-content">
<div v-html="content" ref="html"></div>
</div>
</template>
<style lang="scss" scoped>
@import '@/styles/html/richText.scss';
/* 内容区右侧的话题展示区 */
.w-e-text-container {
.kungalgame-topic-content {
/** 100 + 20 + 20 + 1 = 141px */
width: calc(100% - 141px);
font-size: 15px;
padding: 17px;
border-left: 1px solid var(--kungalgame-blue-1);
color: var(--kungalgame-font-color-3);
}
.kungalgame-topic-content {
border-radius: 5px;
padding: 0 10px;
margin-top: 20px;
overflow-x: auto;
:deep(*) {
max-width: v-bind(width);
max-width: 100%;
overflow-y: scroll;
}
:deep(a) {
color: var(--kungalgame-blue-5);
border-bottom: 1.5px solid var(--kungalgame-trans-white-9);
&:hover {
border-bottom: 1.5px solid var(--kungalgame-blue-5);
}
}
:deep(span) {
text-shadow: none;
}
/* 下面全部是 wangEditor 原生样式 */
:deep(p, li) {
white-space: pre-wrap; /* 保留空格 */
}
:deep(blockquote) {
border-left: 8px solid var(--kungalgame-blue-1);
padding: 10px 10px;
margin: 10px 0;
background-color: var(--kungalgame-trans-blue-0);
}
:deep(pre > code) {
display: block;
padding: 10px;
}
:deep(code) {
font-family: monospace;
background-color: var(--kungalgame-trans-blue-0);
padding: 3px;
border-radius: 3px;
text-shadow: none;
box-shadow: var(--shadow);
}
:deep(table) {
border-collapse: collapse;
}
:deep(td, th) {
border: 1px solid var(--kungalgame-blue-4);
min-width: 50px;
height: 20px;
}
:deep(th) {
background-color: var(--kungalgame-trans-blue-0);
}
:deep(ul, ol) {
padding-left: 20px;
}
:deep(input[type='checkbox']) {
margin-right: 5px;
}
/**
* 过滤 prism 相关样式的代码
*/
/* 这一步把 prism 的背景过滤掉 */
:deep(pre) {
padding: 0;
border: 1px solid var(--kungalgame-blue-4);
background-color: var(--kungalgame-trans-white-9);
}
:deep(.token) {
background-color: var(--kungalgame-trans-white-9);
}
:deep(.toolbar) {
top: 10px;
right: 10px;
display: flex;
& > .toolbar-item {
/* 这里直接根据 DOM 结构写的,写的不是很明了,要怪就怪写 prism 插件的人吧 hhh */
button,
& > span {
background-color: var(--kungalgame-trans-white-9);
border: 1px solid var(--kungalgame-blue-4);
color: var(--kungalgame-blue-4);
box-shadow: unset;
margin-left: 10px;
border-radius: 0;
padding: 2px 5px;
&:hover {
background-color: var(--kungalgame-blue-4);
color: var(--kungalgame-white);
}
}
button {
cursor: pointer;
&:focus {
color: var(--kungalgame-red-4);
}
}
}
}
}
@media (max-width: 700px) {
.w-e-text-container {
.kungalgame-topic-content {
width: 100%;
}
}

View file

@ -5,10 +5,42 @@ import vue from '@vitejs/plugin-vue'
import { visualizer } from 'rollup-plugin-visualizer'
// 导入 vite tsx 支持
import vueJsx from '@vitejs/plugin-vue-jsx'
// 导入 prismjs 高亮
import { prismjsPlugin } from 'vite-plugin-prismjs'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue(), visualizer() as PluginOption, vueJsx()],
plugins: [
vue(),
visualizer() as PluginOption,
vueJsx(),
prismjsPlugin({
languages: [
'javascript',
'css',
'markup',
'go',
'java',
'python',
'nginx',
'yaml',
'bash',
'sql',
'git',
'markdown',
'php',
'vim',
],
plugins: [
'line-numbers',
'show-language',
'toolbar',
'copy-to-clipboard',
],
theme: 'okaidia',
css: true,
}),
],
/* src 别名为 @ */
resolve: {
alias: {