feat: Add Markdown Preview functionality
This commit is contained in:
+1
-1
File diff suppressed because one or more lines are too long
+126
-4
@@ -185,6 +185,84 @@
|
||||
}
|
||||
|
||||
/* Textarea */
|
||||
#editor-panel {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#preview-panel {
|
||||
display: none;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: auto;
|
||||
border-left: 1px solid var(--border);
|
||||
background: #fff;
|
||||
color: #222;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
#preview-panel.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#preview {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
overflow-wrap: break-word;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
#preview h1,
|
||||
#preview h2,
|
||||
#preview h3,
|
||||
#preview h4,
|
||||
#preview h5,
|
||||
#preview h6 {
|
||||
color: #222222;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
#preview p,
|
||||
#preview li,
|
||||
#preview pre,
|
||||
#preview code,
|
||||
#preview blockquote {
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
#preview pre {
|
||||
background: #111111;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#preview code {
|
||||
color: #ffffff;
|
||||
padding: 2px 4px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#preview a {
|
||||
color: #7db4ff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#preview blockquote {
|
||||
border-left: 4px solid #555555;
|
||||
padding-left: 12px;
|
||||
margin: 0.75rem 0;
|
||||
}
|
||||
|
||||
#preview blockquote p {
|
||||
color: #555555;
|
||||
}
|
||||
|
||||
#editor {
|
||||
flex: 1;
|
||||
background: var(--bg);
|
||||
@@ -522,6 +600,7 @@
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -647,8 +726,13 @@
|
||||
|
||||
<!-- Main Editor Area -->
|
||||
<div id="editor-area">
|
||||
<div id="line-numbers"></div>
|
||||
<textarea id="editor" spellcheck="false" autocomplete="off" autocorrect="off" autocapitalize="off"></textarea>
|
||||
<div id="editor-panel">
|
||||
<div id="line-numbers"></div>
|
||||
<textarea id="editor" spellcheck="false" autocomplete="off" autocorrect="off" autocapitalize="off"></textarea>
|
||||
</div>
|
||||
<div id="preview-panel" class="preview-panel">
|
||||
<div id="preview"></div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Overlay -->
|
||||
<div id="dialog-overlay">
|
||||
@@ -952,6 +1036,8 @@
|
||||
const gotoBar = document.getElementById("goto-bar");
|
||||
const gotoInput = document.getElementById("goto-input");
|
||||
const menuBar = document.getElementById("menu-bar");
|
||||
const previewPanel = document.getElementById("preview-panel");
|
||||
const preview = document.getElementById("preview");
|
||||
|
||||
// -- State
|
||||
let fileName = "Untitled";
|
||||
@@ -964,13 +1050,14 @@
|
||||
let lastReplace = "";
|
||||
let notifTimer = null;
|
||||
let replaceMode = false;
|
||||
let markdownPreview = false;
|
||||
|
||||
// -- Initial Content
|
||||
editor.value = [
|
||||
"Pascar",
|
||||
"======",
|
||||
"",
|
||||
"A faithful offline recreation of the classic MS-DOS Editor",
|
||||
"A browser-based offline recreation of the classic MS-DOS Editor for the modern needs of today.",
|
||||
"Runs entirely in your browser - no server, no internet.",
|
||||
"",
|
||||
"QUICK START",
|
||||
@@ -1037,6 +1124,36 @@
|
||||
(isModified ? "* " : "") + fileName + " - Pascar";
|
||||
}
|
||||
|
||||
function isMarkdownFile(name) {
|
||||
return /\.md$/i.test(name);
|
||||
}
|
||||
|
||||
function setMarkdownPreview(active) {
|
||||
markdownPreview = active;
|
||||
previewPanel.classList.toggle("active", active);
|
||||
if (active) {
|
||||
renderMarkdownPreview();
|
||||
} else {
|
||||
preview.innerHTML = "";
|
||||
}
|
||||
}
|
||||
|
||||
function renderMarkdownPreview() {
|
||||
if (!markdownPreview) return;
|
||||
if (typeof marked === "undefined") {
|
||||
preview.innerHTML =
|
||||
"<p><em>Marked.js failed to load. Markdown preview is unavailable.</em></p>";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
preview.innerHTML = marked.parse(editor.value || "");
|
||||
} catch (err) {
|
||||
preview.innerHTML =
|
||||
`<p><em>Error rendering markdown:</em></p><pre>${escHtml(err.message)}</pre>`;
|
||||
}
|
||||
}
|
||||
|
||||
// -- Notifications
|
||||
function showNotif(msg, dur = 2500) {
|
||||
notif.textContent = msg;
|
||||
@@ -1049,6 +1166,7 @@
|
||||
editor.addEventListener("input", () => {
|
||||
isModified = true;
|
||||
updateAll();
|
||||
if (markdownPreview) renderMarkdownPreview();
|
||||
});
|
||||
editor.addEventListener("keyup", updateStatus);
|
||||
editor.addEventListener("click", updateStatus);
|
||||
@@ -1450,6 +1568,7 @@
|
||||
fileName = "Untitled";
|
||||
fileHandle = null;
|
||||
isModified = false;
|
||||
setMarkdownPreview(false);
|
||||
updateAll();
|
||||
editor.focus();
|
||||
}
|
||||
@@ -1499,6 +1618,7 @@
|
||||
fileName = file.name;
|
||||
editor.value = await file.text();
|
||||
isModified = false;
|
||||
setMarkdownPreview(isMarkdownFile(fileName));
|
||||
updateAll();
|
||||
editor.focus();
|
||||
showNotif(`Opened: ${fileName}`);
|
||||
@@ -1519,6 +1639,7 @@
|
||||
reader.onload = (e) => {
|
||||
editor.value = e.target.result;
|
||||
isModified = false;
|
||||
setMarkdownPreview(isMarkdownFile(fileName));
|
||||
updateAll();
|
||||
editor.focus();
|
||||
showNotif(`Opened: ${fileName}`);
|
||||
@@ -1582,6 +1703,7 @@
|
||||
await writable.write(editor.value);
|
||||
await writable.close();
|
||||
isModified = false;
|
||||
setMarkdownPreview(isMarkdownFile(fileName));
|
||||
updateStatus();
|
||||
showNotif(`Saved: ${fileName}`);
|
||||
} catch (err) {
|
||||
@@ -1988,4 +2110,4 @@
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
Reference in New Issue
Block a user