diff --git a/assets/scss/index.dark.scss b/assets/scss/index.dark.scss
index 72fed23..7409f57 100644
--- a/assets/scss/index.dark.scss
+++ b/assets/scss/index.dark.scss
@@ -1,6 +1,6 @@
-html.dark body{
+html.dark body {
/* 自定义深色背景颜色 */
- --custom-app-color:#ffffff;
+ --custom-app-color: #ffffff;
--custom-app-bg-color: #000000;
}
@@ -18,4 +18,35 @@ html.dark .post-detail-content-box table th {
html.dark .post-detail-content-box table td {
border-color: #ccc;
background-color: #161616;
+}
+
+/** dark code */
+html.dark .post-detail-content-box .hljs {
+ color: #ffffff;
+ background-color: #161616 !important;
+ border: 1px solid #ccc !important;
+}
+
+html.dark code {
+ color: #2fd945 !important;
+}
+
+html.dark .hljs-keyword,
+html.dark .hljs-selector-tag,
+html.dark .hljs-built_in,
+html.dark .hljs-name,
+html.dark .hljs-tag {
+ color: #539dc5 !important;
+}
+
+html.dark .post-detail-content-box .hljs-string,
+html.dark .post-detail-content-box .hljs-title,
+html.dark .post-detail-content-box .hljs-section,
+html.dark .post-detail-content-box .hljs-attribute,
+html.dark .post-detail-content-box .hljs-literal,
+html.dark .post-detail-content-box .hljs-template-tag,
+html.dark .post-detail-content-box .hljs-template-variable,
+html.dark .post-detail-content-box .hljs-type,
+html.dark .post-detail-content-box .hljs-addition {
+ color: #2fd945 !important;
}
\ No newline at end of file
diff --git a/package.json b/package.json
index e174f62..150e4d0 100644
--- a/package.json
+++ b/package.json
@@ -29,6 +29,7 @@
"@fortawesome/vue-fontawesome": "^3.0.1",
"arraybuffer-xml-parser": "^0.6.0",
"element-plus": "^2.2.15",
+ "highlight.js": "^11.6.0",
"pinia": "^2.0.23",
"showdown": "^2.1.0",
"vue": "^3.2.40",
diff --git a/pages/post/[postid].vue b/pages/post/[postid].vue
index e844586..dd88ada 100644
--- a/pages/post/[postid].vue
+++ b/pages/post/[postid].vue
@@ -36,11 +36,9 @@
-->
-
diff --git a/plugins/fontawesomePlugin.ts b/plugins/fontawesome.ts
similarity index 100%
rename from plugins/fontawesomePlugin.ts
rename to plugins/fontawesome.ts
diff --git a/plugins/hljs/codecopy/codecopy.css b/plugins/hljs/codecopy/codecopy.css
new file mode 100644
index 0000000..9208d60
--- /dev/null
+++ b/plugins/hljs/codecopy/codecopy.css
@@ -0,0 +1,54 @@
+.hljs-copy-wrapper {
+ position: relative;
+ overflow: hidden;
+}
+.hljs-copy-wrapper:hover .hljs-copy-button,
+.hljs-copy-button:focus {
+ transform: translateX(0);
+}
+.hljs-copy-button {
+ position: absolute;
+ transform: translateX(calc(100% + 1.125em));
+ top: 1em;
+ right: 1em;
+ width: 2rem;
+ height: 2rem;
+ text-indent: -9999px; /* Hide the inner text */
+ color: #fff;
+ border-radius: 0.25rem;
+ border: 1px solid #ffffff22;
+ /*background-color: #2d2b57;*/
+ background-color: #0d6efd;
+ background-image: url('data:image/svg+xml;utf-8,');
+ background-repeat: no-repeat;
+ background-position: center;
+ transition: background-color 200ms ease, transform 200ms ease-out;
+ cursor: pointer;
+}
+.hljs-copy-button:hover {
+ border-color: #ffffff44;
+}
+.hljs-copy-button:active {
+ border-color: #ffffff66;
+}
+.hljs-copy-button[data-copied="true"] {
+ text-indent: 0px; /* Shows the inner text */
+ width: auto;
+ background-image: none;
+}
+@media (prefers-reduced-motion) {
+ .hljs-copy-button {
+ transition: none;
+ }
+}
+
+/* visually-hidden */
+.hljs-copy-alert {
+ clip: rect(0 0 0 0);
+ clip-path: inset(50%);
+ height: 1px;
+ overflow: hidden;
+ position: absolute;
+ white-space: nowrap;
+ width: 1px;
+}
diff --git a/plugins/hljs/codecopy/index.js b/plugins/hljs/codecopy/index.js
new file mode 100644
index 0000000..e84cd75
--- /dev/null
+++ b/plugins/hljs/codecopy/index.js
@@ -0,0 +1,95 @@
+/**
+ * @file highlight-copy.js
+ * @author Arron Hunt
+ * @copyright Copyright 2021. All rights reserved.
+ */
+
+/**
+ * Adds a copy button to highlightjs code blocks
+ */
+export class CopyButtonPlugin {
+ /**
+ * Create a new CopyButtonPlugin class instance
+ * @param {Object} [options] - Functions that will be called when a copy event fires
+ * @param {CopyCallback} [options.callback]
+ * @param {Hook} [options.hook]
+ */
+ constructor(options = {}) {
+ // this.hook = options.hook;
+ // this.callback = options.callback;
+ }
+
+ // @ts-ignore
+ "after:highlightElement"({el, text}) {
+ // Create the copy button and append it to the codeblock.
+ const button = Object.assign(document.createElement("button"), {
+ innerHTML: "Copy",
+ className: "hljs-copy-button"
+ });
+ // @ts-ignore
+ button.dataset.copied = false;
+ el.parentElement.classList.add("hljs-copy-wrapper");
+ el.parentElement.appendChild(button);
+
+ // Add a custom proprety to the code block so that the copy button can reference and match its background-color value.
+ el.parentElement.style.setProperty(
+ "--hljs-theme-background",
+ window.getComputedStyle(el).backgroundColor
+ );
+
+ button.onclick = function () {
+ if (!navigator.clipboard) return;
+
+ let newText = text;
+ // @ts-ignore
+ // eslint-disable-next-line no-undef
+ // if (hook && typeof hook === "function") {
+ // // @ts-ignore
+ // // eslint-disable-next-line no-undef
+ // newText = hook(text, el) || text;
+ // }
+
+ navigator.clipboard
+ .writeText(newText)
+ .then(function () {
+ button.innerHTML = "复制成功";
+ // @ts-ignore
+ button.dataset.copied = true;
+
+ let alert = Object.assign(document.createElement("div"), {
+ role: "status",
+ className: "hljs-copy-alert",
+ innerHTML: "复制到剪贴板"
+ });
+ el.parentElement.appendChild(alert);
+
+ setTimeout(() => {
+ button.innerHTML = "Copy";
+ // @ts-ignore
+ button.dataset.copied = false;
+ el.parentElement.removeChild(alert);
+ // @ts-ignore
+ alert = null;
+ }, 2000);
+ })
+ .then(function () {
+ // @ts-ignore
+ // eslint-disable-next-line no-undef
+ if (typeof callback === "function") return callback(newText, el);
+ });
+ };
+ }
+}
+
+/**
+ * @typedef {function} CopyCallback
+ * @param {string} text - The raw text copied to the clipboard.
+ * @param {HTMLElement} el - The code block element that was copied from.
+ * @returns {undefined}
+ */
+/**
+ * @typedef {function} Hook
+ * @param {string} text - The raw text copied to the clipboard.
+ * @param {HTMLElement} el - The code block element that was copied from.
+ * @returns {string|undefined}
+ */
diff --git a/plugins/hljs/vue-hljs/main.js b/plugins/hljs/vue-hljs/main.js
new file mode 100644
index 0000000..a82046a
--- /dev/null
+++ b/plugins/hljs/vue-hljs/main.js
@@ -0,0 +1,78 @@
+import Hljs from "highlight.js";
+import {CopyButtonPlugin} from "../codecopy";
+import "../codecopy/codecopy.css";
+import "./vs.css";
+
+const vueHljs = {};
+
+vueHljs.install = Vue => {
+ // 代码复制
+ Hljs.addPlugin(
+ new CopyButtonPlugin()
+ );
+
+ Vue.directive("highlight", el => {
+ const blocks = el.querySelectorAll("pre code");
+ Array.prototype.forEach.call(blocks, Hljs.highlightBlock);
+
+ // 代码选项卡
+ // 代码块
+ const codeGroups = el.querySelectorAll("code-group");
+ // 处理每个代码块
+ codeGroups.forEach(group => {
+ // 防止重复添加
+ if (group.getElementsByTagName("ul").length === 0) {
+ const newNode = document.createElement("ul");
+ newNode.setAttribute("class", "code-tab");
+
+ const codeBlocks = group.querySelectorAll("code-block");
+ codeBlocks.forEach(block => {
+ const title = block.attributes.getNamedItem("title")?.value;
+ const active = block.attributes.getNamedItem("active")?.value;
+ const isActive = active !== undefined;
+ // console.log(block.attributes.length)
+ // console.log(title)
+ // console.log(isActive)
+
+ const item = document.createElement("li");
+ item.setAttribute(
+ "class",
+ isActive ? "code-tab-item current" : "code-tab-item"
+ );
+ item.innerHTML = title || "";
+ item.addEventListener("click", function (event) {
+ const targetElement = event.target;
+ // 选择状态
+ // console.log(codeBlocks[0].innerHTML)
+ const allLis = targetElement.parentElement.querySelectorAll("li");
+ allLis.forEach(li => {
+ li.setAttribute("class", "code-tab-item");
+ });
+ targetElement.setAttribute("class", "code-tab-item current");
+
+ // 设置tab
+ codeBlocks.forEach(cb => {
+ if (
+ cb.attributes.getNamedItem("title")?.value ===
+ targetElement.innerHTML
+ ) {
+ cb.setAttribute("active", "");
+ } else {
+ cb.removeAttribute("active");
+ }
+ });
+ // console.log(targetElement.innerHTML);
+ });
+
+ newNode.append(item);
+ });
+
+ const firstBlock = codeBlocks[0];
+ firstBlock?.parentNode?.insertBefore(newNode, firstBlock);
+ // console.log("tab")
+ }
+ });
+ });
+};
+
+export default vueHljs;
diff --git a/plugins/hljs/vue-hljs/vs.css b/plugins/hljs/vue-hljs/vs.css
new file mode 100644
index 0000000..50897d3
--- /dev/null
+++ b/plugins/hljs/vue-hljs/vs.css
@@ -0,0 +1,52 @@
+code{
+ font-family: "LXGW WenKai","Wenquanyi Micro Hei","Wenquanyi Micro Hei Mono","Microsoft YaHei", "PT Sans", "-apple-system", "Liberation Mono", monospace, dejavu sans mono,Fira Code,Microsoft Yahei,Consolas,Courier New,monospace,Menlo,Monaco !important;
+ font-size: 14px; color: red;
+}
+.hljs {
+ font-family: "LXGW WenKai","Wenquanyi Micro Hei","Wenquanyi Micro Hei Mono","Microsoft YaHei", "PT Sans", "-apple-system", "Liberation Mono", monospace, dejavu sans mono,Fira Code,Microsoft Yahei,Consolas,Courier New,monospace,Menlo,Monaco !important;
+ font-size: 14px;
+ display: block;
+ overflow-x: auto;
+ padding: .5em;
+ line-height: 1.6;
+ color: black;
+ background-color: #f5f5f5!important;
+ /*border: 1px solid #ccc!important;*/
+ border-radius: 3px!important;
+}
+
+.hljs-comment, .hljs-quote, .hljs-variable {
+ color: #008000
+}
+
+.hljs-keyword, .hljs-selector-tag, .hljs-built_in, .hljs-name, .hljs-tag {
+ color: #00f
+}
+
+.hljs-string, .hljs-title, .hljs-section, .hljs-attribute, .hljs-literal, .hljs-template-tag, .hljs-template-variable, .hljs-type, .hljs-addition {
+ color: #a31515
+}
+
+.hljs-deletion, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-meta {
+ color: #2b91af
+}
+
+.hljs-doctag {
+ color: #808080
+}
+
+.hljs-attr {
+ color: #f00
+}
+
+.hljs-symbol, .hljs-bullet, .hljs-link {
+ color: #00b0e8
+}
+
+.hljs-emphasis {
+ font-style: italic
+}
+
+.hljs-strong {
+ font-weight: bold
+}
diff --git a/plugins/hljs/vue-hljs/vs2015.css b/plugins/hljs/vue-hljs/vs2015.css
new file mode 100644
index 0000000..f6a1f38
--- /dev/null
+++ b/plugins/hljs/vue-hljs/vs2015.css
@@ -0,0 +1,95 @@
+code{
+ font-family: "LXGW WenKai","Wenquanyi Micro Hei","Wenquanyi Micro Hei Mono","Microsoft YaHei", "PT Sans", "-apple-system", "Liberation Mono", monospace, dejavu sans mono,Fira Code,Microsoft Yahei,Consolas,Courier New,monospace,Menlo,Monaco !important;
+ color: #D69D85;
+ font-size: 14px;
+}
+.hljs {
+ font-family: "LXGW WenKai","Wenquanyi Micro Hei","Wenquanyi Micro Hei Mono","Microsoft YaHei", "PT Sans", "-apple-system", "Liberation Mono", monospace, dejavu sans mono,Fira Code,Microsoft Yahei,Consolas,Courier New,monospace,Menlo,Monaco !important;
+ font-size: 14px;
+ display: block;
+ overflow-x: auto;
+ padding: .5em;
+ background: #181818;
+ color: #DCDCDC;
+ border: solid 1px #181818;
+ border-radius: 5px;
+ line-height: 1.6;
+}
+
+.hljs-keyword, .hljs-literal, .hljs-symbol, .hljs-name {
+ color: #569CD6
+}
+
+.hljs-link {
+ color: #569CD6;
+ text-decoration: underline
+}
+
+.hljs-built_in, .hljs-type {
+ color: #4EC9B0
+}
+
+.hljs-number, .hljs-class {
+ color: #B8D7A3
+}
+
+.hljs-string, .hljs-meta-string {
+ color: #D69D85
+}
+
+.hljs-regexp, .hljs-template-tag {
+ color: #9A5334
+}
+
+.hljs-subst, .hljs-function, .hljs-title, .hljs-params, .hljs-formula {
+ color: #DCDCDC
+}
+
+.hljs-comment, .hljs-quote {
+ color: #57A64A;
+ font-style: italic
+}
+
+.hljs-doctag {
+ color: #608B4E
+}
+
+.hljs-meta, .hljs-meta-keyword, .hljs-tag {
+ color: #9B9B9B
+}
+
+.hljs-variable, .hljs-template-variable {
+ color: #BD63C5
+}
+
+.hljs-attr, .hljs-attribute, .hljs-builtin-name {
+ color: #9CDCFE
+}
+
+.hljs-section {
+ color: gold
+}
+
+.hljs-emphasis {
+ font-style: italic
+}
+
+.hljs-strong {
+ font-weight: bold
+}
+
+.hljs-bullet, .hljs-selector-tag, .hljs-selector-id, .hljs-selector-class, .hljs-selector-attr, .hljs-selector-pseudo {
+ color: #D7BA7D
+}
+
+.hljs-addition {
+ background-color: #144212;
+ display: inline-block;
+ width: 100%
+}
+
+.hljs-deletion {
+ background-color: #600;
+ display: inline-block;
+ width: 100%
+}
diff --git a/plugins/vuehljs.ts b/plugins/vuehljs.ts
new file mode 100644
index 0000000..82e24b0
--- /dev/null
+++ b/plugins/vuehljs.ts
@@ -0,0 +1,9 @@
+import vueHljs from "~/plugins/hljs/vue-hljs/main.js";
+
+/**
+ * 代码高亮插件
+ */
+export default defineNuxtPlugin((nuxtApp) => {
+ // vueHljs
+ nuxtApp.vueApp.use(vueHljs)
+});
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index c866e7d..fb5ae00 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2547,6 +2547,11 @@ hash-sum@^2.0.0:
resolved "https://registry.npmmirror.com/hash-sum/-/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a"
integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==
+highlight.js@^11.6.0:
+ version "11.6.0"
+ resolved "https://registry.npmmirror.com/highlight.js/-/highlight.js-11.6.0.tgz#a50e9da05763f1bb0c1322c8f4f755242cff3f5a"
+ integrity sha512-ig1eqDzJaB0pqEvlPVIpSSyMaO92bH1N2rJpLMN/nX396wTpDA4Eq0uK+7I/2XG17pFaaKE0kjV/XPeGt7Evjw==
+
hookable@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/hookable/-/hookable-5.3.0.tgz#eabdd7bef9e04cb3505c49153b669d5d53974e7d"