From 6c8355d5ad383d8a7eab8dd88f49769198da95cc Mon Sep 17 00:00:00 2001 From: Danielo Rodriguez Date: Mon, 11 Dec 2023 01:22:42 +0100 Subject: [PATCH] chore: better UI for creating notes from forms --- src/main.ts | 17 ++++--- src/suggesters/NewNoteModal.ts | 84 ++++++++++++++++++++++++++++++++++ src/suggesters/suggestArray.ts | 27 ----------- src/utils/files.ts | 8 ++++ 4 files changed, 102 insertions(+), 34 deletions(-) create mode 100644 src/suggesters/NewNoteModal.ts delete mode 100644 src/suggesters/suggestArray.ts diff --git a/src/main.ts b/src/main.ts index fc466fcc..fa3311fa 100644 --- a/src/main.ts +++ b/src/main.ts @@ -14,9 +14,10 @@ import * as E from "fp-ts/Either"; import { pipe } from "fp-ts/function"; import * as A from "fp-ts/Array" import { settingsStore } from "./store/store"; -import { FormPickerModal } from "./suggesters/FormPickerModal"; import { O } from "@std"; import { executeTemplate } from "./core/template/templateParser"; +import { NewNoteModal } from "./suggesters/NewNoteModal"; +import { file_exists } from "./utils/files"; type ViewType = typeof EDIT_FORM_VIEW | typeof MANAGE_FORMS_VIEW; @@ -203,11 +204,11 @@ export default class ModalFormPlugin extends Plugin { * @param name the name of the note, without the extension * @returns a unique name for the note, full path including the extension */ - getUniqueNoteName(name: string): string { + getUniqueNoteName(name: string, destinationFolder?: string): string { const defaultNotesFolder = this.app.fileManager.getNewFileParent('', 'note.md') - let destinationPath = `${defaultNotesFolder.path}/${name}.md` + let destinationPath = `${destinationFolder || defaultNotesFolder.path}/${name}.md` let i = 1; - while (this.app.vault.getAbstractFileByPath(destinationPath)) { + while (file_exists(destinationPath, this.app)) { destinationPath = `${defaultNotesFolder.path}/${name}-${i}.md` i++; } @@ -232,12 +233,14 @@ export default class ModalFormPlugin extends Plugin { return O.none; }) ) - const onFormSelected = async (form: FormWithTemplate) => { + const onFormSelected = async (form: FormWithTemplate, noteName: string, destinationFolder: string) => { const formData = await this.api.openForm(form); - const newNoteFullPath = this.getUniqueNoteName(form.name); + const newNoteFullPath = this.getUniqueNoteName(noteName, destinationFolder); this.app.vault.create(newNoteFullPath, executeTemplate(form.template, formData.getData())) } - const picker = new FormPickerModal(this.app, formsWithTemplates, onFormSelected); + const picker = new NewNoteModal(this.app, formsWithTemplates, ({ form, folder, noteName }) => { + onFormSelected(form, noteName, folder) + }); picker.open(); } diff --git a/src/suggesters/NewNoteModal.ts b/src/suggesters/NewNoteModal.ts new file mode 100644 index 00000000..07d338e7 --- /dev/null +++ b/src/suggesters/NewNoteModal.ts @@ -0,0 +1,84 @@ +import { App, Modal, Setting } from "obsidian"; +import { FormWithTemplate } from "src/core/formDefinition"; +import { FolderSuggest } from "./suggestFolder"; +import { GenericSuggest } from "./suggestGeneric"; +import { log_notice } from "src/utils/Log"; + +interface OnSelectArgs { + form: FormWithTemplate + folder: string + noteName: string +} + +const formSuggester = (app: App, input: HTMLInputElement, forms: FormWithTemplate[], onChange: (form: FormWithTemplate) => void) => new GenericSuggest( + app, + input, + new Set(forms), + { + getSuggestions: (inputStr, forms) => { + return forms.filter((form) => form.name.toLowerCase().contains(inputStr)) + }, + renderSuggestion: (form, el) => { + el.setText(form.name) + }, + selectSuggestion: (form) => { + onChange(form) + return form.name + } + } +) + +export class NewNoteModal extends Modal { + constructor(app: App, private forms: FormWithTemplate[], protected onSelected: (args: OnSelectArgs) => void) { + super(app); + } + + onOpen() { + let destinationFolder = '' + let form: FormWithTemplate + let noteName = '' + const { contentEl } = this; + // h1 is a title + contentEl.createEl('h1', { text: 'New Note from form' }) + + // picker of existing forms + new Setting(contentEl).addSearch((element) => { + formSuggester(this.app, element.inputEl, this.forms, (value) => { + form = value + }) + }).setDesc('Pick a form') + // picker for destination folder + new Setting(contentEl).addSearch((element) => { + new FolderSuggest(element.inputEl, this.app) + element.onChange((value) => { + destinationFolder = value + }) + }).setName('Destination folder') + new Setting(contentEl).addText((element) => { + element.onChange((value) => { + noteName = value + }) + }).setName('Note name'); + // button to create new form + new Setting(contentEl).addButton((element) => { + element.setButtonText('Create new note') + element.onClick(() => { + if (!form || !destinationFolder.trim() || !noteName.trim()) { + log_notice('Missing fields', 'Please fill all the fields') + return + } + this.close() + this.onSelected({ + form, + folder: destinationFolder.trim(), + noteName: noteName.trim(), + }) + }) + }) + } + + onClose() { + const { contentEl } = this; + contentEl.empty(); + } +} diff --git a/src/suggesters/suggestArray.ts b/src/suggesters/suggestArray.ts deleted file mode 100644 index ecf2024b..00000000 --- a/src/suggesters/suggestArray.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { AbstractInputSuggest, App } from "obsidian"; - -export class ArraySuggest extends AbstractInputSuggest { - content: Set; - - constructor(app: App, private inputEl: HTMLInputElement, content: Set) { - super(app, inputEl); - this.content = content; - } - - getSuggestions(inputStr: string): string[] { - const lowerCaseInputStr = inputStr.toLowerCase(); - return [...this.content].filter((content) => - content.contains(lowerCaseInputStr) - ); - } - - renderSuggestion(content: string, el: HTMLElement): void { - el.setText(content); - } - - selectSuggestion(content: string): void { - this.inputEl.value = content; - this.inputEl.trigger("input"); - this.close(); - } -} diff --git a/src/utils/files.ts b/src/utils/files.ts index 4eed9b2f..bc5078c1 100644 --- a/src/utils/files.ts +++ b/src/utils/files.ts @@ -73,3 +73,11 @@ export function get_tfiles_from_folder(folder_str: string, app: App): Either app.vault.getAbstractFileByPath(path), + (value) => value !== null + ) +}