切换markdown渲染为cm6

This commit is contained in:
2026-07-03 15:06:53 +08:00
parent a37bb0a894
commit 8f95ea3d39
8 changed files with 917 additions and 688 deletions

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref } from "vue";
import { ref, onMounted, onUnmounted } from "vue";
import { listen } from "@tauri-apps/api/event";
import { invoke } from "@tauri-apps/api/core";
import MarkdownEditor from "./components/MarkdownEditor.vue";
@@ -23,6 +23,72 @@ interface DirEntry {
const folderPath = ref("");
const dirEntries = ref<DirEntry[]>([]);
// ---- editor zoom (Ctrl+scroll) ----
const ZOOM_MIN = 0.7;
const ZOOM_MAX = 1.5;
const ZOOM_STEP = 0.1;
function loadZoomPref(): number {
try {
const stored = localStorage.getItem("editor-zoom");
if (stored) {
const val = parseFloat(stored);
if (!isNaN(val) && val >= ZOOM_MIN && val <= ZOOM_MAX) return val;
}
} catch { /* localStorage unavailable */ }
return 1.0;
}
const editorZoom = ref(loadZoomPref());
const showZoomIndicator = ref(false);
let zoomIndicatorTimer: ReturnType<typeof setTimeout> | null = null;
function applyZoomCssVars() {
document.documentElement.style.setProperty("--editor-zoom", String(editorZoom.value));
}
function saveZoomPref() {
try { localStorage.setItem("editor-zoom", String(editorZoom.value)); } catch { /* noop */ }
}
function onEditorWheel(e: WheelEvent) {
if (!e.ctrlKey && !e.metaKey) return;
e.preventDefault();
const delta = e.deltaY < 0 ? ZOOM_STEP : -ZOOM_STEP;
const next = Math.round((editorZoom.value + delta) * 10) / 10;
editorZoom.value = Math.min(ZOOM_MAX, Math.max(ZOOM_MIN, next));
applyZoomCssVars();
saveZoomPref();
// Show zoom indicator and reset timer
showZoomIndicator.value = true;
if (zoomIndicatorTimer) clearTimeout(zoomIndicatorTimer);
zoomIndicatorTimer = setTimeout(() => { showZoomIndicator.value = false; }, 1500);
}
// ---- full-width mode ----
function loadFullWidthPref(): boolean {
try {
return localStorage.getItem("editor-full-width") === "true";
} catch { return false; }
}
const isFullWidth = ref(loadFullWidthPref());
function onToggleFullWidth(val: boolean) {
isFullWidth.value = val;
try { localStorage.setItem("editor-full-width", String(val)); } catch { /* noop */ }
}
onMounted(() => {
applyZoomCssVars();
window.addEventListener("wheel", onEditorWheel, { passive: false });
});
onUnmounted(() => {
window.removeEventListener("wheel", onEditorWheel);
if (zoomIndicatorTimer) clearTimeout(zoomIndicatorTimer);
});
function stripMarkdown(md: string): string {
return md
// Remove images ![alt](url)
@@ -55,13 +121,11 @@ function onUpdate(md: string) {
}
function onHeadingClick(heading: { text: string; level: number }) {
// Navigate to heading in the editor — find the heading element and scroll it into view
const editorEl = document.querySelector(".tiptap-editor .ProseMirror");
if (!editorEl) return;
const headingTags = editorEl.querySelectorAll("h1, h2, h3");
for (const el of headingTags) {
if (el.textContent?.trim() === heading.text && el.tagName === `H${heading.level}`) {
// Navigate to heading in the CodeMirror editor
const className = `.cm-lp-h${heading.level}`;
const headingEls = document.querySelectorAll(className);
for (const el of headingEls) {
if (el.textContent?.trim() === heading.text) {
el.scrollIntoView({ behavior: "smooth", block: "start" });
break;
}
@@ -202,21 +266,34 @@ listen("menu-event", (event) => {
:entries="dirEntries"
:content="content"
:current-file-path="currentFilePath"
:is-full-width="isFullWidth"
@heading-click="onHeadingClick"
@open-folder="onOpenFolder"
@toggle-folder="onToggleFolder"
@open-file="onOpenFile"
@toggle-full-width="onToggleFullWidth"
/>
<!-- Right: Editor area -->
<main class="flex-1 flex flex-col overflow-y-auto">
<main class="flex-1 flex flex-col overflow-hidden relative">
<MarkdownEditor
v-model="content"
:model-value="content"
:is-full-width="isFullWidth"
placeholder="输入 Markdown 内容... 支持标题、粗体、斜体、代码块等 ✨"
@update:model-value="onUpdate"
@save-shortcut="doSave"
class="flex-1 w-full"
/>
<!-- Zoom indicator -->
<Transition name="zoom-fade">
<div
v-if="showZoomIndicator"
class="fixed top-4 right-4 z-50 px-2.5 py-1 rounded-md bg-[#38342e]/80 text-white text-xs font-medium pointer-events-none select-none backdrop-blur-sm"
>
{{ Math.round(editorZoom * 100) }}%
</div>
</Transition>
</main>
</div>
<footer class="border-t border-[#e8e4da] bg-[#f4f1eb]/60 backdrop-blur-sm">
@@ -243,4 +320,15 @@ listen("menu-event", (event) => {
</div>
</template>
<style>
.zoom-fade-enter-active,
.zoom-fade-leave-active {
transition: opacity 0.2s ease;
}
.zoom-fade-enter-from,
.zoom-fade-leave-to {
opacity: 0;
}
</style>