Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/parent_folder_on_folder_input #351

Merged
merged 2 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions EXAMPLE_VAULT/.obsidian/plugins/modal-form/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -343,31 +343,28 @@
{
"title": "Frontmatter example",
"name": "frontmatter",
"version": "1",
"fields": [
{
"name": "title",
"label": "",
"description": "",
"isRequired": false,
"input": {
"type": "text",
"allowUnknownValues": false,
"hidden": false
},
"isRequired": false
}
},
{
"name": "tags",
"label": "",
"description": "",
"isRequired": false,
"input": {
"type": "tag",
"allowUnknownValues": false,
"hidden": false
},
"isRequired": false
"type": "tag"
}
}
]
],
"version": "1"
}
]
}
25 changes: 25 additions & 0 deletions docs/blog/posts/modal form showcase.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
title: Modal form showcase thread
Author: Danielo
date: 2024-12-12
tags: announcement
---

Hello everyone.

I've created this thread so people can share their awesome workflows using modal forms.

A lot of times people that open feature requests mention they need such feature to complete their workflow, or that such feature will make their workflow simpler, and then they mention what their workflow is about and then blow my mind.

I saw other plugins also have similar threads, so I decided to create this one to encourage people to share their forms and how are they using them.

Anyone is free to provide their experiences however they want, but here are some suggestions that I think will make each post even more useful for everyone:

- Start the thread with a summary of the workflow or the problem you are solving.
- If you can, export your form as a JSON file and share it in the thread using a code block. This will make it easier for others to use your form.
- If you can, share a screenshot of your form. This will make it easier for others to understand what your form looks like and makes it a lot more engaging.
- If you are calling the form from a template, please share the template as well in another code block.
- If you are okay about including your post as part of the example vault on modal form repository, please say so, then others just looking at the plugin repository can see your example.

And that's all.
I'm very excited about seeing all the different workflows and how you use modal forms, and I hope this will be a great way to share and learn from each other.
1 change: 1 addition & 0 deletions src/core/input/InputDefinitionSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export const InputNoteFromFolderSchema = object({
});
export const InputFolderSchema = object({
type: literal("folder"),
parentFolder: optional(string([toTrimmed()])),
// TODO: allow exclude option
});
export const InputDataviewSourceSchema = object({
Expand Down
19 changes: 12 additions & 7 deletions src/suggesters/suggestFolder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,30 @@
import { AbstractInputSuggest, App, TAbstractFile, TFolder } from "obsidian";

export class FolderSuggest extends AbstractInputSuggest<TFolder> {

constructor(
public inputEl: HTMLInputElement,
public app: App,
private parentFolder?: string,
) {
super(app, inputEl);
}

getSuggestions(inputStr: string): TFolder[] {
const abstractFiles = this.app.vault.getAllLoadedFiles();
const lowerCaseInputStr = inputStr.toLowerCase();

const folders: TFolder[] = abstractFiles.reduce((acc, folder: TAbstractFile) => {
if (
folder instanceof TFolder &&
folder.path.toLowerCase().contains(lowerCaseInputStr)
) {
acc.push(folder)
if (!(folder instanceof TFolder)) return acc;

const folderPath = folder.path.toLowerCase();
const matchesInput = folderPath.contains(lowerCaseInputStr);
const matchesParent =
!this.parentFolder || folderPath.startsWith(this.parentFolder.toLowerCase());

if (matchesInput && matchesParent) {
acc.push(folder);
}
return acc
return acc;
}, [] as TFolder[]);

return folders;
Expand Down
8 changes: 7 additions & 1 deletion src/views/FormBuilder.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
import FormRow from "./components/FormRow.svelte";
import InputBuilderDataview from "./components/inputBuilderDataview.svelte";
import InputBuilderDocumentBlock from "./components/InputBuilderDocumentBlock.svelte";
import InputBuilderFile from "./components/InputBuilderFile.svelte";
import InputFolder from "./components/InputBuilderFolder.svelte";
import InputBuilderImage from "./components/InputBuilderImage.svelte";
import InputBuilderFile from "./components/InputBuilderFile.svelte";
import InputBuilderSelect from "./components/InputBuilderSelect.svelte";
import Tabs from "./components/Tabs.svelte";
import TemplateEditor from "./components/TemplateEditor.svelte";
Expand Down Expand Up @@ -349,6 +349,12 @@
bind:folder={field.input.folder}
notifyChange={onChange}
/>
{:else if field.input.type === "folder"}
<InputFolder
{index}
bind:folder={field.input.parentFolder}
notifyChange={onChange}
/>
{:else if field.input.type === "dataview"}
<InputBuilderDataview
{index}
Expand Down
11 changes: 9 additions & 2 deletions src/views/components/Form/InputFolder.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,23 @@
import { useSetting } from "./useObsidianSetting";
export let field: FieldDefinition;
export let value: Writable<FieldValue>;
export let parentFolder: string | undefined;
export let app: App;
let search_: SearchComponent | undefined;
function customizer(setting: Setting) {
setting.addSearch((component) => {
new FolderSuggest(component.inputEl, app);
new FolderSuggest(component.inputEl, app, parentFolder);
search_ = component;
component.onChange((v) => {
$value = v;
$value = v.trim();
});
});
setting.infoEl.appendChild(
createSpan({
cls: "setting-item-description",
text: parentFolder ? `Searching in: ${parentFolder}` : "",
}),
);
}
$: if (search_) {
search_.setValue($value as string);
Expand Down
7 changes: 6 additions & 1 deletion src/views/components/Form/RenderField.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@
{:else if definition.input.type === "toggle"}
<ObsidianToggle field={definition} {value} />
{:else if definition.input.type === "folder"}
<InputFolder field={definition} {value} {app} />
<InputFolder
field={definition}
parentFolder={definition.input.parentFolder}
{value}
{app}
/>
{:else if definition.input.type === "dataview"}
<InputDataview field={definition} input={definition.input} {value} {errors} {app} />
{:else if definition.input.type === "note"}
Expand Down
11 changes: 4 additions & 7 deletions src/views/components/InputBuilderFolder.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
* This component is just to select a folder, not notes inside the folder
*/
export let index: number;
export let folder: string = "";
export let folder: string | undefined;
// This is just used to notify the parent component that the value has changed
// it is useful for example to persis the intermediary state of the form
export let notifyChange: () => void;
function searchFolder(element: HTMLElement) {
new Setting(element).addSearch((search) => {
search.setPlaceholder("Select a folder");
search.setValue(folder);
search.setValue(folder || "");
new FolderSuggest(search.inputEl, app);
search.onChange((value) => {
folder = value;
folder = value.trim() || undefined;
notifyChange();
});
});
Expand All @@ -24,10 +24,7 @@
</script>

<!-- The autocomplete input will be inside the first div, so we remove some styles with the utility classes -->
<div
class="modal-form flex column gap1 remove-padding remove-border fix-suggest"
use:searchFolder
>
<div class="modal-form flex column gap1 remove-padding remove-border fix-suggest" use:searchFolder>
<label for={id}>Source Folder</label>
</div>

Expand Down
Loading