Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf94697d07 |
20
frontend/package-lock.json
generated
20
frontend/package-lock.json
generated
@@ -13,7 +13,9 @@
|
|||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"bootstrap": "^5.3.0",
|
"bootstrap": "^5.3.0",
|
||||||
"dompurify": "^3.0.0",
|
"dompurify": "^3.0.0",
|
||||||
|
"highlight.js": "^11.11.1",
|
||||||
"marked": "^9.0.0",
|
"marked": "^9.0.0",
|
||||||
|
"marked-highlight": "^2.2.3",
|
||||||
"pinia": "^2.1.0",
|
"pinia": "^2.1.0",
|
||||||
"vue": "^3.3.0",
|
"vue": "^3.3.0",
|
||||||
"vue-router": "^4.2.0"
|
"vue-router": "^4.2.0"
|
||||||
@@ -1433,6 +1435,15 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/highlight.js": {
|
||||||
|
"version": "11.11.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz",
|
||||||
|
"integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ini": {
|
"node_modules/ini": {
|
||||||
"version": "1.3.8",
|
"version": "1.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||||
@@ -1556,6 +1567,15 @@
|
|||||||
"node": ">= 16"
|
"node": ">= 16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/marked-highlight": {
|
||||||
|
"version": "2.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/marked-highlight/-/marked-highlight-2.2.3.tgz",
|
||||||
|
"integrity": "sha512-FCfZRxW/msZAiasCML4isYpxyQWKEEx44vOgdn5Kloae+Qc3q4XR7WjpKKf8oMLk7JP9ZCRd2vhtclJFdwxlWQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"marked": ">=4 <18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/math-intrinsics": {
|
"node_modules/math-intrinsics": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
|
|||||||
@@ -15,7 +15,9 @@
|
|||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"bootstrap": "^5.3.0",
|
"bootstrap": "^5.3.0",
|
||||||
"dompurify": "^3.0.0",
|
"dompurify": "^3.0.0",
|
||||||
|
"highlight.js": "^11.11.1",
|
||||||
"marked": "^9.0.0",
|
"marked": "^9.0.0",
|
||||||
|
"marked-highlight": "^2.2.3",
|
||||||
"pinia": "^2.1.0",
|
"pinia": "^2.1.0",
|
||||||
"vue": "^3.3.0",
|
"vue": "^3.3.0",
|
||||||
"vue-router": "^4.2.0"
|
"vue-router": "^4.2.0"
|
||||||
|
|||||||
@@ -25,6 +25,70 @@ body,
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.markdown-body table {
|
||||||
|
width: 100%;
|
||||||
|
margin: 1rem 0;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body th,
|
||||||
|
.markdown-body td {
|
||||||
|
padding: 0.7rem 0.9rem;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
text-align: left;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body th {
|
||||||
|
font-weight: 600;
|
||||||
|
background: #f3f6fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body tr:nth-child(even) td {
|
||||||
|
background: #fbfcfe;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body table code {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body blockquote {
|
||||||
|
margin: 1rem 0;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
border-left: 4px solid #748ffc;
|
||||||
|
background: #f8f9ff;
|
||||||
|
color: #334155;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body blockquote > :last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre {
|
||||||
|
margin: 1rem 0;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
background: #111827;
|
||||||
|
color: #f9fafb;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre code {
|
||||||
|
background: transparent;
|
||||||
|
color: inherit;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body code {
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-size: 0.95em;
|
||||||
|
padding: 0.1rem 0.3rem;
|
||||||
|
border-radius: 0.35rem;
|
||||||
|
background: #f1f3f5;
|
||||||
|
}
|
||||||
|
|
||||||
/* Scrollbar styling */
|
/* Scrollbar styling */
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 8px;
|
width: 8px;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
<div :class="showFileExplorer ? 'col-12 col-md-4 mt-3 mt-md-0' : 'col-12 col-md-6 mt-3 mt-md-0'">
|
<div :class="showFileExplorer ? 'col-12 col-md-4 mt-3 mt-md-0' : 'col-12 col-md-6 mt-3 mt-md-0'">
|
||||||
<div class="preview-pane border rounded p-3">
|
<div class="preview-pane border rounded p-3">
|
||||||
<div v-html="renderedMarkdown"></div>
|
<div class="markdown-body" v-html="renderedMarkdown"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -96,10 +96,9 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, watch, onBeforeUnmount, onMounted, nextTick } from "vue";
|
import { ref, computed, watch, onBeforeUnmount, onMounted, nextTick } from "vue";
|
||||||
import { marked } from "marked";
|
|
||||||
import DOMPurify from "dompurify";
|
import DOMPurify from "dompurify";
|
||||||
import { useSettingsStore } from "../stores/settingsStore";
|
import { useSettingsStore } from "../stores/settingsStore";
|
||||||
import { preprocessMarkdown } from "../utils/markdown.js";
|
import { renderMarkdown } from "../utils/markdown.js";
|
||||||
import FileExplorer from "./FileExplorer.vue";
|
import FileExplorer from "./FileExplorer.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -138,7 +137,7 @@ const saveState = ref("saved");
|
|||||||
const saveStateTimeout = ref(null);
|
const saveStateTimeout = ref(null);
|
||||||
|
|
||||||
const renderedMarkdown = computed(() => {
|
const renderedMarkdown = computed(() => {
|
||||||
const html = marked.parse(preprocessMarkdown(editingNote.value.content || ""));
|
const html = renderMarkdown(editingNote.value.content || "");
|
||||||
return DOMPurify.sanitize(html);
|
return DOMPurify.sanitize(html);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -30,9 +30,8 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import { marked } from "marked";
|
|
||||||
import DOMPurify from "dompurify";
|
import DOMPurify from "dompurify";
|
||||||
import { preprocessMarkdown } from "../utils/markdown.js";
|
import { renderMarkdown } from "../utils/markdown.js";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
note: {
|
note: {
|
||||||
@@ -50,7 +49,7 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const renderedMarkdown = computed(() => {
|
const renderedMarkdown = computed(() => {
|
||||||
const html = marked.parse(preprocessMarkdown(props.note.content || ""));
|
const html = renderMarkdown(props.note.content || "");
|
||||||
return DOMPurify.sanitize(html);
|
return DOMPurify.sanitize(html);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import router from "./router";
|
|||||||
import App from "./App.vue";
|
import App from "./App.vue";
|
||||||
import "bootstrap/dist/css/bootstrap.min.css";
|
import "bootstrap/dist/css/bootstrap.min.css";
|
||||||
import "@mdi/font/css/materialdesignicons.min.css";
|
import "@mdi/font/css/materialdesignicons.min.css";
|
||||||
|
import "highlight.js/styles/github-dark.min.css";
|
||||||
import "./assets/styles/main.css";
|
import "./assets/styles/main.css";
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
|
|||||||
@@ -1,3 +1,19 @@
|
|||||||
|
import { marked } from "marked";
|
||||||
|
import { markedHighlight } from "marked-highlight";
|
||||||
|
import hljs from "highlight.js/lib/common";
|
||||||
|
|
||||||
|
marked.use(
|
||||||
|
markedHighlight({
|
||||||
|
langPrefix: "hljs language-",
|
||||||
|
highlight(code, lang) {
|
||||||
|
if (lang && hljs.getLanguage(lang)) {
|
||||||
|
return hljs.highlight(code, { language: lang }).value;
|
||||||
|
}
|
||||||
|
return hljs.highlightAuto(code).value;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preprocesses markdown content to support extended image size syntax:
|
* Preprocesses markdown content to support extended image size syntax:
|
||||||
*
|
*
|
||||||
@@ -24,3 +40,7 @@ export function preprocessMarkdown(content) {
|
|||||||
return `<img ${attrs}>`;
|
return `<img ${attrs}>`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function renderMarkdown(content) {
|
||||||
|
return marked.parse(preprocessMarkdown(content || ""), { gfm: true });
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user