diff --git a/package.json b/package.json index eb1bae1..4f92964 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "license": "MIT", "devDependencies": { "@tsconfig/svelte": "^3.0.0", + "@types/lodash-es": "^4.17.6", "@types/node": "^16.11.6", "@typescript-eslint/eslint-plugin": "^5.18.0", "@typescript-eslint/parser": "^5.18.0", @@ -35,6 +36,7 @@ "typescript": "^4.6.3" }, "dependencies": { + "lodash-es": "^4.17.21", "minisearch": "^5.0.0-beta1" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 275e171..2b0de27 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2,6 +2,7 @@ lockfileVersion: 5.3 specifiers: '@tsconfig/svelte': ^3.0.0 + '@types/lodash-es': ^4.17.6 '@types/node': ^16.11.6 '@typescript-eslint/eslint-plugin': ^5.18.0 '@typescript-eslint/parser': ^5.18.0 @@ -15,6 +16,7 @@ specifiers: eslint-plugin-node: 11.1.0 eslint-plugin-promise: 5.0.0 eslint-plugin-svelte3: ^3.4.1 + lodash-es: ^4.17.21 minisearch: ^5.0.0-beta1 obsidian: latest prettier: ^2.6.2 @@ -25,10 +27,12 @@ specifiers: typescript: ^4.6.3 dependencies: + lodash-es: 4.17.21 minisearch: 5.0.0-beta1 devDependencies: '@tsconfig/svelte': 3.0.0 + '@types/lodash-es': 4.17.6 '@types/node': 16.11.26 '@typescript-eslint/eslint-plugin': 5.18.0_2e93aa916703472007e9b5dfec98785b '@typescript-eslint/parser': 5.18.0_eslint@7.12.1+typescript@4.6.3 @@ -164,6 +168,16 @@ packages: resolution: {integrity: sha1-7ihweulOEdK4J7y+UnC86n8+ce4=} dev: true + /@types/lodash-es/4.17.6: + resolution: {integrity: sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==} + dependencies: + '@types/lodash': 4.14.181 + dev: true + + /@types/lodash/4.14.181: + resolution: {integrity: sha512-n3tyKthHJbkiWhDZs3DkhkCzt2MexYHXlX0td5iMplyfwketaOeKboEVBqzceH7juqvEg3q5oUoBFxSLu7zFag==} + dev: true + /@types/node/16.11.26: resolution: {integrity: sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ==} dev: true @@ -1547,6 +1561,10 @@ packages: path-exists: 3.0.0 dev: true + /lodash-es/4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + dev: false + /lodash.merge/4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true diff --git a/src/CmpInput.svelte b/src/CmpInput.svelte index be65d3a..0086ef2 100644 --- a/src/CmpInput.svelte +++ b/src/CmpInput.svelte @@ -1,19 +1,50 @@ diff --git a/src/CmpModal.svelte b/src/CmpModal.svelte index 319907a..124e9c9 100644 --- a/src/CmpModal.svelte +++ b/src/CmpModal.svelte @@ -1,18 +1,23 @@ - +
{#each $resultNotes as result (result.path)} - + {/each}
diff --git a/src/CmpNoteResult.svelte b/src/CmpNoteResult.svelte index 213a24b..6d4dcb9 100644 --- a/src/CmpNoteResult.svelte +++ b/src/CmpNoteResult.svelte @@ -1,20 +1,22 @@ -
+
- {@html title} + {@html note.basename} - {nbMatches} {nbMatches > 1 ? 'matches' : 'match'} + {note.matches.length} {note.matches.length > 1 ? "matches" : "match"}
- {@html content} + {@html note.content}
diff --git a/src/modal.ts b/src/modal.ts index 1983965..9ea07e4 100644 --- a/src/modal.ts +++ b/src/modal.ts @@ -1,142 +1,25 @@ -import { MarkdownView, Modal, TFile } from 'obsidian' -import type { ResultNote } from './globals' -import type OmnisearchPlugin from './main' -import CmpNoteResult from './CmpNoteResult.svelte' -import CmpModal from './CmpModal.svelte' -import { escapeHTML, escapeRegex, getAllIndexes, highlighter } from './utils' -import { selectedNoteId } from './stores' +import { Modal } from "obsidian"; +import type OmnisearchPlugin from "./main"; +import CmpModal from "./CmpModal.svelte"; export class OmnisearchModal extends Modal { - private plugin: OmnisearchPlugin - private mutationObserver?: MutationObserver - private cmp: CmpModal - constructor(plugin: OmnisearchPlugin) { - super(plugin.app) - this.plugin = plugin - this.modalEl.addClass('omnisearch-modal', 'prompt') - this.modalEl.replaceChildren() // Remove all the default Modal's children + super(plugin.app); + this.modalEl.addClass("omnisearch-modal", "prompt"); + this.modalEl.replaceChildren(); // Remove all the default Modal's children - this.cmp = new CmpModal({ + new CmpModal({ target: this.modalEl, props: { + modal: this, plugin, }, - }) - - // this.modalEl.addClass('omnisearch-modal') - - // this.setPlaceholder('Type to search through your notes') - - // this.setInstructions([ - // { command: '↑↓', purpose: 'to navigate' }, - // { command: '↵', purpose: 'to open' }, - // { command: 'ctrl ↵', purpose: 'to open in a new pane' }, - // { command: 'shift ↵', purpose: 'to create' }, - // { command: 'esc', purpose: 'to dismiss' }, - // ]) + }); } onOpen(): void { - this.containerEl.style.border = '1px solid red' - this.modalEl.style.border = '1px solid blue' - this.contentEl.style.border = '1px solid green' - // this.inputEl.focus() - // this.inputEl.onkeydown = this.onKeydown.bind(this) - // Reload last search, if any - // if (this.plugin.lastSearch) { - // const event = new Event('input', { - // bubbles: true, - // cancelable: true, - // }) - // // this.inputEl.value = this.plugin.lastSearch - // // this.inputEl.dispatchEvent(event) - // // this.inputEl.select() - // // this.inputEl.spellcheck = false - // } - - // this.setupObserver(this.modalEl) - } - - - // async onKeydown(ev: KeyboardEvent): Promise { - // if (ev.key === 'ArrowRight') { - // console.log('TODO: open in-note search') - // return - // } - // const noteId = get(selectedNoteId) - // if (ev.key !== 'Enter' || !noteId) return - - // if (ev.ctrlKey || ev.metaKey) { - // // Open in a new pane - // await this.app.workspace.openLinkText(noteId, '', true) - // } - // else if (ev.shiftKey) { - // // Create a note - // try { - // const file = await this.app.vault.create( - // this.inputEl.value + '.md', - // '# ' + this.inputEl.value, - // ) - // await this.app.workspace.openLinkText(file.path, '') - // } - // catch (e) { - // if (e instanceof Error && e.message === 'File already exists.') { - // // Open the existing file instead of creating it - // await this.app.workspace.openLinkText(this.inputEl.value, '') - // } - // else { - // console.error(e) - // } - // } - // } - // this.close() - // } - - /** - * Observes the modal element to keep track of which search result is currently selected - * @param modalEl - */ - setupObserver(modalEl: HTMLElement): void { - this.mutationObserver = new MutationObserver(events => { - const record = events.find(event => - (event.target as HTMLDivElement).classList.contains('is-selected'), - ) - const id = - (record?.target?.firstChild as HTMLElement)?.getAttribute( - 'data-note-id', - ) ?? null - if (id) { - selectedNoteId.set(id) - } - }) - this.mutationObserver.observe(modalEl, { - attributes: true, - subtree: true, - }) - } - - async onChooseSuggestion(item: ResultNote): Promise { - const file = this.app.vault.getAbstractFileByPath(item.path) as TFile - // const fileCache = this.app.metadataCache.getFileCache(file) - // console.log(fileCache) - const content = (await this.app.vault.cachedRead(file)).toLowerCase() - const offset = content.indexOf( - item.matches[item.occurence].match.toLowerCase(), - ) - await this.app.workspace.openLinkText(item.path, '') - - const view = this.app.workspace.getActiveViewOfType(MarkdownView) - if (!view) { - throw new Error('OmniSearch - No active MarkdownView') - } - const pos = view.editor.offsetToPos(offset) - pos.ch = 0 - - view.editor.setCursor(pos) - view.editor.scrollIntoView({ - from: { line: pos.line - 10, ch: 0 }, - to: { line: pos.line + 10, ch: 0 }, - }) + // this.containerEl.style.border = '1px solid red' + // this.modalEl.style.border = '1px solid blue' + // this.contentEl.style.border = '1px solid green' } } diff --git a/src/stores.ts b/src/stores.ts index 308b41a..7fd271c 100644 --- a/src/stores.ts +++ b/src/stores.ts @@ -1,6 +1,34 @@ -import { writable } from 'svelte/store' +import { get, writable } from 'svelte/store' import type { ResultNote } from './globals' -export const selectedNoteId = writable('') +// export const selectedNoteId = writable('') export const searchQuery = writable('') export const resultNotes = writable([]) + +function createSelectedNote() { + const { subscribe, set, update } = writable(null) + return { + subscribe, + set, + next: () => + update(v => { + const notes = get(resultNotes) + let id = notes.findIndex(n => n.path === v?.path) + if (!notes.length) return null + if (id === -1) return notes[0] + id = id < notes.length - 1 ? id + 1 : 0 + return notes[id] + }), + previous: () => + update(v => { + const notes = get(resultNotes) + let id = notes.findIndex(n => n.path === v?.path) + if (!notes.length) return null + if (id === -1) return notes[0] + id = id > 0 ? id - 1 : notes.length - 1 + return notes[id] + }), + } +} + +export const selectedNote = createSelectedNote()