find feature

This commit is contained in:
nicwands
2026-03-26 16:33:03 -04:00
parent 2ab76684cc
commit 86146f1ecf
4 changed files with 26 additions and 99 deletions

View File

@@ -56,6 +56,9 @@ onMounted(async () => {
content: note.content || [],
onUpdate: onUpdate,
})
// Clear any highlights from find feature
editor.value.chain().selectAll().unsetHighlight().run()
})
onBeforeUnmount(() => {
editor.value?.destroy?.()
@@ -152,10 +155,10 @@ defineExpose({
background: currentColor;
}
}
mark {
.highlighted {
background: var(--theme-accent);
color: var(--theme-bg);
padding: 0 0.2em;
border-radius: 0.2em;
}
ul[data-type='taskList'] {

View File

@@ -1,34 +1,20 @@
<template>
<div v-if="visible" class="note-find">
<div class="find-bar">
<!-- <input
@keydown.enter="findNext"
@keydown.escape="close"
ref="inputRef"
/> -->
<search-input
v-model="searchQuery"
placeholder="Find..."
ref="inputRef"
@keydown.escape="close"
/>
<span class="match-count">
{{ currentMatch + 1 }} / {{ matches.length }}
</span>
<button @click="findPrev" :disabled="matches.length === 0">
</button>
<button @click="findNext" :disabled="matches.length === 0">
</button>
<button @click="close"></button>
</div>
</div>
</template>
<script setup>
import { ref, watch, nextTick } from 'vue'
import { ref, watch, nextTick, onBeforeUnmount, onMounted } from 'vue'
import SearchInput from '@/components/SearchInput.vue'
import { Highlight } from '@tiptap/extension-highlight'
const props = defineProps({
editor: {
@@ -45,7 +31,6 @@ const emit = defineEmits(['close'])
const searchQuery = ref('')
const matches = ref([])
const currentMatch = ref(0)
const inputRef = ref(null)
const findInDocument = () => {
@@ -78,82 +63,25 @@ const findInDocument = () => {
})
matches.value = foundMatches
currentMatch.value = 0
if (foundMatches.length > 0) {
highlightMatch(0)
scrollToMatch(0)
}
highlightMatches()
}
const highlightMatch = (index) => {
if (!props.editor || !matches.value[index]) return
const { from, to } = matches.value[index]
const highlightMatches = () => {
if (!props.editor || !matches.value) return
matches.value.forEach(({ from, to }) => {
props.editor
.chain()
.setTextSelection({ from, to })
.setHighlight({ color: 'var(--theme-accent)' })
.run()
inputRef.value?.focus()
})
}
const clearHighlights = () => {
if (!props.editor) return
const { state } = props.editor
const { doc } = state
doc.descendants((node, pos) => {
if (node.marks && node.marks.length > 0) {
node.marks.forEach((mark) => {
if (mark.type.name === 'highlight') {
props.editor.chain().focus().unsetHighlight().run()
}
})
}
})
props.editor.commands.unsetHighlight()
}
const scrollToMatch = (index) => {
if (!props.editor || !matches.value[index]) return
const { from } = matches.value[index]
props.editor.commands.setTextSelection({ from, to: from })
const dom = props.editor.view.dom
const selection = window.getSelection()
if (selection && selection.rangeCount > 0) {
const range = selection.getRangeAt(0)
range.commonAncestorContainer.scrollIntoView({
behavior: 'smooth',
block: 'center',
})
}
}
const findNext = () => {
if (matches.value.length === 0) return
clearHighlights()
currentMatch.value = (currentMatch.value + 1) % matches.value.length
highlightMatch(currentMatch.value)
scrollToMatch(currentMatch.value)
}
const findPrev = () => {
if (matches.value.length === 0) return
clearHighlights()
currentMatch.value =
(currentMatch.value - 1 + matches.value.length) % matches.value.length
highlightMatch(currentMatch.value)
scrollToMatch(currentMatch.value)
props.editor.chain().selectAll().unsetHighlight().run()
}
const close = () => {
@@ -170,27 +98,25 @@ watch(
await nextTick()
inputRef.value?.focus()
if (props.editor && searchQuery.value) {
console.log('visible change')
findInDocument()
}
}
},
)
watch(
() => props.editor,
(newEditor) => {
if (newEditor && props.visible && searchQuery.value) {
console.log('editor change')
findInDocument()
}
},
)
watch(searchQuery, () => {
console.log('search change')
findInDocument()
})
onMounted(() => clearHighlights())
onBeforeUnmount(() => clearHighlights())
</script>
<style lang="scss">

View File

@@ -13,12 +13,6 @@
>
Italic
</button>
<button
@click="editor.chain().focus().toggleHighlight().run()"
:class="{ active: editor.isActive('highlight') }"
>
Highlight
</button>
</div>
</bubble-menu>
</template>

View File

@@ -33,7 +33,11 @@ export const extensions = [
}),
TaskList,
TaskItem,
Highlight,
Highlight.configure({
HTMLAttributes: {
class: 'highlighted',
},
}),
Markdown,
CodeBlockLowlight.configure({
lowlight,