feat: 添加搜索框
This commit is contained in:
@@ -6,12 +6,12 @@
|
|||||||
import { ref, onMounted, onBeforeUnmount, watch, shallowRef, computed } from 'vue';
|
import { ref, onMounted, onBeforeUnmount, watch, shallowRef, computed } from 'vue';
|
||||||
import { EditorState, Compartment } from '@codemirror/state';
|
import { EditorState, Compartment } from '@codemirror/state';
|
||||||
import { useAppearanceStore } from '../stores/appearance.store';
|
import { useAppearanceStore } from '../stores/appearance.store';
|
||||||
import { EditorView, keymap, lineNumbers, highlightActiveLineGutter, highlightActiveLine, drawSelection, dropCursor } from '@codemirror/view';
|
import { EditorView, keymap, lineNumbers, highlightActiveLineGutter, highlightActiveLine, drawSelection, dropCursor } from '@codemirror/view';
|
||||||
import { syntaxHighlighting, defaultHighlightStyle, indentOnInput, bracketMatching, foldGutter, foldKeymap } from '@codemirror/language';
|
import { syntaxHighlighting, defaultHighlightStyle, indentOnInput, bracketMatching, foldGutter, foldKeymap } from '@codemirror/language';
|
||||||
import { vscodeDark } from '@uiw/codemirror-theme-vscode';
|
import { vscodeDark } from '@uiw/codemirror-theme-vscode';
|
||||||
import { history, historyKeymap, defaultKeymap } from '@codemirror/commands';
|
import { history, historyKeymap, defaultKeymap } from '@codemirror/commands';
|
||||||
import { autocompletion, closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
|
import { autocompletion, closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
|
||||||
import { highlightSelectionMatches } from '@codemirror/search';
|
import { highlightSelectionMatches, searchKeymap, openSearchPanel } from '@codemirror/search'; // + Import search functionalities
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
@@ -121,11 +121,12 @@ const createEditorState = (doc: string, languageExtension: any) => {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
keymap.of([
|
keymap.of([
|
||||||
...closeBracketsKeymap,
|
...closeBracketsKeymap,
|
||||||
...defaultKeymap,
|
...defaultKeymap,
|
||||||
...historyKeymap,
|
...historyKeymap,
|
||||||
...foldKeymap,
|
...foldKeymap,
|
||||||
{ key: "Mod-s", run: () => { emit('request-save'); return true; } }
|
...searchKeymap, // + Add search keymap
|
||||||
|
{ key: "Mod-s", run: () => { emit('request-save'); return true; } }
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@@ -271,8 +272,15 @@ watch(() => appearanceStore.currentMobileEditorFontSize, (newSize) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const openSearch = () => {
|
||||||
|
if (view.value) {
|
||||||
|
openSearchPanel(view.value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
focus: () => view.value?.focus(),
|
focus: () => view.value?.focus(),
|
||||||
|
openSearch, // + Expose openSearch method
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ const startHeightPx = ref(0);
|
|||||||
const minWidth = 400; // 最小宽度
|
const minWidth = 400; // 最小宽度
|
||||||
const minHeight = 300; // 最小高度
|
const minHeight = 300; // 最小高度
|
||||||
const encodingSelectRef = ref<HTMLSelectElement | null>(null); // +++ Ref for the select element +++
|
const encodingSelectRef = ref<HTMLSelectElement | null>(null); // +++ Ref for the select element +++
|
||||||
|
const codeMirrorMobileEditorRef = ref<InstanceType<typeof CodeMirrorMobileEditor> | null>(null); // +++ Ref for CodeMirrorMobileEditor +++
|
||||||
|
|
||||||
// --- 计算属性,用于模板绑定 ---
|
// --- 计算属性,用于模板绑定 ---
|
||||||
const popupStyle = computed(() => {
|
const popupStyle = computed(() => {
|
||||||
@@ -422,6 +423,13 @@ const handleEditorScroll = ({ scrollTop, scrollLeft }: { scrollTop: number; scro
|
|||||||
const handleEditorFontSizeUpdate = (newSize: number) => {
|
const handleEditorFontSizeUpdate = (newSize: number) => {
|
||||||
appearanceStore.setEditorFontSize(newSize);
|
appearanceStore.setEditorFontSize(newSize);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// +++ 打开搜索面板 +++
|
||||||
|
const handleOpenSearch = () => {
|
||||||
|
if (codeMirrorMobileEditorRef.value) {
|
||||||
|
codeMirrorMobileEditorRef.value.openSearch();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 关闭弹窗 (保持不变)
|
// 关闭弹窗 (保持不变)
|
||||||
const handleCloseContainer = () => {
|
const handleCloseContainer = () => {
|
||||||
@@ -561,6 +569,17 @@ onBeforeUnmount(() => {
|
|||||||
<button @click="handleSaveRequest" :disabled="currentTabIsSaving || currentTabIsLoading || !!currentTabLoadingError || !activeTab" class="save-btn">
|
<button @click="handleSaveRequest" :disabled="currentTabIsSaving || currentTabIsLoading || !!currentTabLoadingError || !activeTab" class="save-btn">
|
||||||
{{ t('fileManager.actions.save') }}
|
{{ t('fileManager.actions.save') }}
|
||||||
</button>
|
</button>
|
||||||
|
<!-- +++ 移动端搜索按钮 +++ -->
|
||||||
|
<button
|
||||||
|
v-if="props.isMobile && activeTab && !currentTabIsLoading"
|
||||||
|
@click="handleOpenSearch"
|
||||||
|
class="search-btn"
|
||||||
|
:title="t('fileManager.actions.search', 'Search')"
|
||||||
|
>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-search" viewBox="0 0 16 16">
|
||||||
|
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001q.044.06.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1 1 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
<button v-if="!props.isMobile" @click="handleCloseContainer" class="close-editor-btn" :title="t('fileManager.actions.closeEditor')">✖</button>
|
<button v-if="!props.isMobile" @click="handleCloseContainer" class="close-editor-btn" :title="t('fileManager.actions.closeEditor')">✖</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -601,6 +620,7 @@ onBeforeUnmount(() => {
|
|||||||
:language="currentTabLanguage"
|
:language="currentTabLanguage"
|
||||||
class="editor-instance"
|
class="editor-instance"
|
||||||
@request-save="handleSaveRequest"
|
@request-save="handleSaveRequest"
|
||||||
|
ref="codeMirrorMobileEditorRef"
|
||||||
/>
|
/>
|
||||||
<!-- 如果容器可见但没有活动标签页 -->
|
<!-- 如果容器可见但没有活动标签页 -->
|
||||||
<div v-else class="editor-placeholder">{{ t('fileManager.selectFileToEdit') }}</div>
|
<div v-else class="editor-placeholder">{{ t('fileManager.selectFileToEdit') }}</div>
|
||||||
@@ -817,6 +837,27 @@ onBeforeUnmount(() => {
|
|||||||
background-color: #45a049;
|
background-color: #45a049;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* +++ 搜索按钮样式 +++ */
|
||||||
|
.search-btn {
|
||||||
|
background-color: #555; /* 与其他按钮风格类似 */
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 0.4rem 0.6rem; /* 调整内边距以适应图标 */
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
display: inline-flex; /* 使图标居中 */
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.search-btn:hover {
|
||||||
|
background-color: #666;
|
||||||
|
}
|
||||||
|
.search-btn svg {
|
||||||
|
pointer-events: none; /* 防止 SVG 捕获点击事件 */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.save-status {
|
.save-status {
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
padding: 0.2rem 0.5rem;
|
padding: 0.2rem 0.5rem;
|
||||||
|
|||||||
Reference in New Issue
Block a user