feat: 优化选择面板、查找面板交互,添加查找忽略大小写开关(#231)

This commit is contained in:
pipipi-pikachu 2023-10-28 22:41:17 +08:00
parent 6aa6acaafa
commit 3450843878
3 changed files with 47 additions and 16 deletions

View File

@ -18,6 +18,8 @@ interface SearchTableResult {
type SearchResult = SearchTextResult | SearchTableResult
type Modifiers = 'g' | 'gi'
export default () => {
const mainStore = useMainStore()
const slidesStore = useSlidesStore()
@ -28,10 +30,12 @@ export default () => {
const replaceWord = ref('')
const searchResults = ref<SearchResult[]>([])
const searchIndex = ref(-1)
const modifiers = ref<Modifiers>('g')
const search = () => {
const textList: SearchResult[] = []
const matchRegex = new RegExp(searchWord.value, 'g')
const matchRegex = new RegExp(searchWord.value, modifiers.value)
const textRegex = /(<([^>]+)>)/g
for (const slide of slides.value) {
@ -116,7 +120,7 @@ export default () => {
type TextInfoList = ReturnType<typeof getTextInfoList>
const getMatchList = (content: string, keyword: string) => {
const reg = new RegExp(keyword, 'g')
const reg = new RegExp(keyword, modifiers.value)
const matchList = []
let match = reg.exec(content)
while (match) {
@ -154,7 +158,7 @@ export default () => {
const highlightTableText = (nodes: NodeListOf<Element>, index: number) => {
for (const node of nodes) {
node.innerHTML = node.innerHTML.replace(new RegExp(searchWord.value, 'g'), () => {
node.innerHTML = node.innerHTML.replace(new RegExp(searchWord.value, modifiers.value), () => {
return `<mark data-index=${index++}>${searchWord.value}</mark>`
})
}
@ -393,13 +397,15 @@ export default () => {
searchResults.value = []
searchIndex.value = -1
}
watch(searchWord, () => {
const reset = () => {
searchIndex.value = -1
searchResults.value = []
if (!searchWord.value) clearMarks()
})
}
watch(searchWord, reset)
watch(slideIndex, () => {
nextTick(() => {
@ -417,15 +423,22 @@ export default () => {
})
onBeforeUnmount(clearMarks)
const toggleModifiers = () => {
modifiers.value = modifiers.value === 'g' ? 'gi' : 'g'
reset()
}
return {
searchWord,
replaceWord,
searchResults,
searchIndex,
modifiers,
searchNext,
searchPrev,
replace,
replaceAll,
toggleModifiers,
}
}

View File

@ -4,8 +4,8 @@
<IconBack class="handler-item" :class="{ 'disable': !canUndo }" v-tooltip="'撤销'" @click="undo()" />
<IconNext class="handler-item" :class="{ 'disable': !canRedo }" v-tooltip="'重做'" @click="redo()" />
<Divider type="vertical" style="height: 20px;" />
<IconMoveOne class="handler-item" v-tooltip="'选择窗格'" @click="openSelectPanel()" />
<IconSearch class="handler-item" v-tooltip="'查找/替换'" @click="openSraechPanel()" />
<IconMoveOne class="handler-item" :class="{ 'active': showSelectPanel }" v-tooltip="'选择窗格'" @click="toggleSelectPanel()" />
<IconSearch class="handler-item" :class="{ 'active': showSearchPanel }" v-tooltip="'查找/替换'" @click="toggleSraechPanel()" />
</div>
<div class="add-element-handler">
@ -116,7 +116,7 @@ import Popover from '@/components/Popover.vue'
import PopoverMenuItem from '@/components/PopoverMenuItem.vue'
const mainStore = useMainStore()
const { creatingElement, creatingCustomShape } = storeToRefs(mainStore)
const { creatingElement, creatingCustomShape, showSelectPanel, showSearchPanel } = storeToRefs(mainStore)
const { canUndo, canRedo } = storeToRefs(useSnapshotStore())
const { redo, undo } = useHistorySnapshot()
@ -191,13 +191,13 @@ const drawLine = (line: LinePoolItem) => {
}
//
const openSelectPanel = () => {
mainStore.setSelectPanelState(true)
const toggleSelectPanel = () => {
mainStore.setSelectPanelState(!showSelectPanel.value)
}
//
const openSraechPanel = () => {
mainStore.setSearchPanelState(true)
const toggleSraechPanel = () => {
mainStore.setSearchPanelState(!showSearchPanel.value)
}
</script>
@ -289,6 +289,7 @@ const openSraechPanel = () => {
.handler-item {
padding: 0 8px;
&.active,
&:not(.disable):hover {
background-color: #f1f1f1;
}

View File

@ -1,7 +1,7 @@
<template>
<MoveablePanel
class="search-panel"
:width="300"
:width="330"
:height="0"
:left="-270"
:top="90"
@ -17,8 +17,14 @@
<template #suffix>
<span class="count">{{searchIndex + 1}}/{{searchResults.length}}</span>
<Divider type="vertical" />
<IconLeft class="next-btn left" @click="searchPrev()" />
<IconRight class="next-btn right" @click="searchNext()" />
<span class="ignore-case"
:class="{ 'active': modifiers === 'g' }"
v-tooltip="'忽略大小写'"
@click="toggleModifiers()"
>Aa</span>
<Divider type="vertical" />
<IconLeft class="next-btn left" @click="searchPrev()" v-tooltip="'上一个'" />
<IconRight class="next-btn right" @click="searchNext()" v-tooltip="'下一个'" />
</template>
</Input>
<Input class="input" v-model:value="replaceWord" placeholder="输入替换内容" @enter="replace()" v-if="type === 'replace'"></Input>
@ -53,10 +59,12 @@ const {
replaceWord,
searchResults,
searchIndex,
modifiers,
searchNext,
searchPrev,
replace,
replaceAll,
toggleModifiers,
} = useSearch()
const type = ref<TypeKey>('search')
@ -98,6 +106,15 @@ watch(type, () => {
margin-right: 8px;
user-select: none;
}
.ignore-case {
font-size: 12px;
user-select: none;
cursor: pointer;
&.active {
color: $themeColor;
}
}
.next-btn {
width: 22px;
height: 100%;