完善编辑功能

This commit is contained in:
2026-07-20 17:47:24 +08:00
parent f725261370
commit 05898a14e0
4 changed files with 41 additions and 104 deletions

View File

@@ -60,9 +60,9 @@
"updatedAt": 1783674217586
},
"topic_20260710-090003_60717bd90da5ec68": {
"stage": 1,
"userTurns": 1,
"basisHash": "cd60850543a6985b",
"updatedAt": 1783700550206
"stage": 3,
"userTurns": 3,
"basisHash": "de6e56c00454cedd",
"updatedAt": 1784540365461
}
}

View File

@@ -50,5 +50,5 @@
"topic_20260710-034724_3c6fb29d8d0a4119": "目录树中鼠标悬浮弹框dropmenu…",
"topic_20260710-054543_5e7c427932aecd7b": "现在在markdown的编辑区域中…",
"topic_20260710-063053_353d579222d3b70b": "这个应用里有一个全局搜索的功能,帮我…",
"topic_20260710-090003_60717bd90da5ec68": "当用户在markdownEditor…"
"topic_20260710-090003_60717bd90da5ec68": "D:\\code\\yurou\\src…"
}

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import {computed, ref, watch, onMounted, onUnmounted, nextTick} from "vue";
import {computed, ref, onMounted, onUnmounted, nextTick} from "vue";
import {listen, type EventCallback, type EventName} from "@tauri-apps/api/event";
import {convertFileSrc, invoke, isTauri} from "@tauri-apps/api/core";
import {getCurrentWindow, type CloseRequestedEvent} from "@tauri-apps/api/window";
@@ -186,7 +186,7 @@ const WORKSPACE_REFRESH_DELAY_MS = 140;
let workspaceRefreshTimer: ReturnType<typeof setTimeout> | null = null;
let workspaceRefreshInFlight = false;
let workspaceRefreshQueued = false;
let syncInFlight = false;
const syncInFlight = ref(false);
let fileOpenRequest = 0;
let saveNoticeTimer: ReturnType<typeof setTimeout> | null = null;
let closeSaveInFlight = false;
@@ -247,7 +247,6 @@ const documentMode = ref<DocumentMode>(defaultDocumentMode.value);
const appTheme = ref<AppTheme>(loadAppTheme());
const renderSingleLineBreaks = ref(loadRenderSingleLineBreaks());
const paragraphIndent = ref(loadParagraphIndent());
const showMoreMenu = ref(false);
const settingsRequest = ref(0);
const settingsInitialPage = ref<"about" | "editor" | "sync">("about");
const markdownEditorRef = ref<{ flushPendingChanges: () => string | undefined; scrollToLine: (line: number) => void } | null>(null);
@@ -398,23 +397,6 @@ function updateAppTheme(theme: AppTheme) {
saveAppTheme(theme);
}
function handleExportPdf() {
showMoreMenu.value = false;
// TODO: implement PDF export
}
function closeMoreMenu() {
showMoreMenu.value = false;
}
watch(showMoreMenu, (val) => {
if (val) {
setTimeout(() => {
document.addEventListener("click", closeMoreMenu, {once: true});
}, 0);
}
});
onMounted(() => {
applyAppTheme(appTheme.value);
applyZoomCssVars();
@@ -503,7 +485,6 @@ function resetMarkdownEditorState() {
saveStatus.value = "";
showOutline.value = false;
documentMode.value = defaultDocumentMode.value;
showMoreMenu.value = false;
editorResetKey.value += 1;
}
@@ -798,36 +779,41 @@ async function refreshCurrentOpenFileFromDisk() {
}
async function runConfiguredSync(trigger: "startup" | "save" | "manual") {
if (!folderPath.value || syncInFlight) return false;
if (!folderPath.value || syncInFlight.value) return false;
const config = await loadSyncConfig();
if (trigger !== "manual" && !shouldRunSync(config, trigger)) return false;
if (!config || config.provider === "none") return false;
if (!config || config.provider === "none") {
if (trigger === "manual") {
showSaveNotice("请先在设置中配置同步方式", "error");
}
return false;
}
if (trigger !== "save") {
const saved = await saveCurrentWorkspaceDocumentBeforeSwitch();
if (!saved) return false;
}
syncInFlight = true;
syncInFlight.value = true;
showSaveNotice("正在同步...", "success");
try {
const result = await invoke<SyncResult>("sync_now", {
workspace: folderPath.value,
config,
});
saveStatus.value = describeSyncResult(result);
setTimeout(() => {
saveStatus.value = "";
}, 3600);
showSaveNotice(describeSyncResult(result), "success");
await refreshWorkspaceTree();
await refreshCurrentOpenFileFromDisk();
return true;
} catch (e) {
console.error("Sync failed:", e);
saveStatus.value = `同步失败: ${e}`;
showSaveNotice(`同步失败: ${e}`, "error");
return false;
} finally {
syncInFlight = false;
syncInFlight.value = false;
}
}
@@ -915,7 +901,6 @@ function openMediaPreview(path: string, fileType: Extract<WorkspaceFileType, "im
hasDraftDocument.value = false;
saveStatus.value = "";
showOutline.value = false;
showMoreMenu.value = false;
editorResetKey.value += 1;
}
@@ -1380,34 +1365,16 @@ async function handleSearchResultClick(filePath: string, lineNumber: number) {
</button>
</div>
<!-- More menu -->
<div v-if="isMarkdownDocument" class="relative">
<!-- Sync button -->
<button
v-if="folderPath"
class="toolbar-btn"
title="更多"
@click="showMoreMenu = !showMoreMenu"
:title="syncInFlight ? '正在同步...' : '同步工作目录'"
:disabled="syncInFlight"
@click="runConfiguredSync('manual')"
>
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
<circle cx="3" cy="8" r="1.5"/>
<circle cx="8" cy="8" r="1.5"/>
<circle cx="13" cy="8" r="1.5"/>
</svg>
<i :class="syncInFlight ? 'ri-loader-4-line sync-spinning' : 'ri-loop-left-line'"></i>
</button>
<div
v-if="showMoreMenu"
class="dropdown-menu"
@click.stop
>
<button class="dropdown-item" @click="handleExportPdf">
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5">
<path d="M5 1h6l4 4v9a1 1 0 01-1 1H2a1 1 0 01-1-1V2a1 1 0 011-1z"/>
<path d="M5 1v4h4"/>
<path d="M5 9h6M5 12h4"/>
</svg>
导出 PDF
</button>
</div>
</div>
</div>
<!-- Window controls -->
@@ -1872,38 +1839,6 @@ async function handleSearchResultClick(filePath: string, lineNumber: number) {
box-shadow: 0 1px 3px var(--app-shadow);
}
.dropdown-menu {
position: absolute;
right: 0;
top: 100%;
margin-top: 4px;
background: var(--app-surface);
border: 1px solid var(--app-border-strong);
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
min-width: 140px;
padding: 4px;
z-index: 50;
}
.dropdown-item {
display: flex;
align-items: center;
gap: 8px;
width: 100%;
padding: 6px 10px;
border-radius: 6px;
font-size: 13px;
color: var(--app-text);
background: transparent;
border: none;
cursor: pointer;
text-align: left;
}
.dropdown-item:hover {
background-color: var(--app-surface-muted);
}
.start-actions {
background:
@@ -1934,4 +1869,15 @@ async function handleSearchResultClick(filePath: string, lineNumber: number) {
text-decoration-color: currentColor;
outline: none;
}
/* Sync button spin animation */
@keyframes sync-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.sync-spinning {
display: inline-block;
animation: sync-spin 1s linear infinite;
}
</style>

View File

@@ -1148,16 +1148,7 @@ defineExpose({
.markdown-preview h3 { font-size: 1.125em; }
.markdown-preview h4 { font-size: 1em; }
.markdown-preview p { margin: 0; text-indent: var(--paragraph-indent, 0); }
.markdown-preview:not(.markdown-mixed) > p + p,
.markdown-mixed
> .markdown-block-paragraph
+ .markdown-block-paragraph
> .markdown-block-preview
> p {
margin-top: 0;
}
.markdown-preview p { margin: 0.8em 0; text-indent: var(--paragraph-indent, 0); }
.markdown-preview strong { font-weight: 700; color: var(--app-text-strong); }
.markdown-preview em { font-style: italic; }