diff --git a/EXAMPLE_VAULT/.obsidian/app.json b/EXAMPLE_VAULT/.obsidian/app.json index 9e26dfe..6abe4c1 100644 --- a/EXAMPLE_VAULT/.obsidian/app.json +++ b/EXAMPLE_VAULT/.obsidian/app.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "alwaysUpdateLinks": true +} \ No newline at end of file diff --git a/EXAMPLE_VAULT/.obsidian/plugins/modal-form/data.json b/EXAMPLE_VAULT/.obsidian/plugins/modal-form/data.json index 47d403e..1fbddba 100644 --- a/EXAMPLE_VAULT/.obsidian/plugins/modal-form/data.json +++ b/EXAMPLE_VAULT/.obsidian/plugins/modal-form/data.json @@ -229,7 +229,7 @@ "isRequired": false, "input": { "type": "document_block", - "body": "return `This field contains several hidden fields`" + "body": "return `This field contains several hidden fields ${form.hidden_text}`" } }, { @@ -264,6 +264,45 @@ } ], "version": "1" + }, + { + "title": "Codeblock examples", + "name": "codeblocks", + "fields": [ + { + "name": "md_block", + "label": "", + "description": "", + "isRequired": false, + "input": { + "type": "markdown_block", + "body": "return `# hello\n- line 1\n- ${form.text}\n- ![[image.png]]`" + } + }, + { + "name": "text", + "label": "", + "description": "", + "isRequired": false, + "input": { + "type": "text", + "hidden": false + } + }, + { + "name": "block_01", + "label": "", + "description": "", + "input": { + "type": "document_block", + "allowUnknownValues": false, + "hidden": false, + "body": "return `${form.text}`" + }, + "isRequired": false + } + ], + "version": "1" } ] } \ No newline at end of file diff --git a/EXAMPLE_VAULT/image.png b/EXAMPLE_VAULT/image.png new file mode 100644 index 0000000..d6227bd Binary files /dev/null and b/EXAMPLE_VAULT/image.png differ diff --git a/src/core/formDefinition.ts b/src/core/formDefinition.ts index e2cd521..95fbc03 100644 --- a/src/core/formDefinition.ts +++ b/src/core/formDefinition.ts @@ -46,6 +46,7 @@ export const InputTypeReadable: Record = { dataview: "Dataview", multiselect: "Multiselect", document_block: "Document block", + markdown_block: "Markdown block", } as const; export function isDataViewSource(input: unknown): input is inputDataviewSource { diff --git a/src/core/input/InputDefinitionSchema.ts b/src/core/input/InputDefinitionSchema.ts index 86f68cd..8bf026d 100644 --- a/src/core/input/InputDefinitionSchema.ts +++ b/src/core/input/InputDefinitionSchema.ts @@ -131,6 +131,15 @@ const DocumentBlock = object({ body: string(), }); +/** + * Same as DocumentBlock, but with accepts and markdown as result + * from the body function + */ +const MarkdownBlock = object({ + type: literal("markdown_block"), + body: string(), +}); + // Codec for all the input types export const InputTypeSchema = union([ InputBasicSchema, @@ -143,6 +152,7 @@ export const InputTypeSchema = union([ InputSelectFixedSchema, MultiselectSchema, DocumentBlock, + MarkdownBlock, ]); export type Input = Output; @@ -165,6 +175,7 @@ export const InputTypeToParserMap: Record> dataview: parseC(InputDataviewSourceSchema), multiselect: parseC(MultiselectSchema), document_block: parseC(DocumentBlock), + markdown_block: parseC(MarkdownBlock), }; //=========== Types derived from schemas @@ -180,6 +191,7 @@ export type inputTag = Output; export type inputType = Output; export type DocumentBlock = Output; +export type MarkdownBlock = Output; export function requiresListOfStrings(input: inputType): boolean { const type = input.type; @@ -193,6 +205,7 @@ export function requiresListOfStrings(input: inputType): boolean { case "folder": case "slider": case "document_block": + case "markdown_block": case "number": case "text": case "date": diff --git a/src/core/input/dependentFields.ts b/src/core/input/dependentFields.ts index f1fcf06..2fbf7b7 100644 --- a/src/core/input/dependentFields.ts +++ b/src/core/input/dependentFields.ts @@ -55,6 +55,7 @@ export function availableConditionsForInput(input: FieldDefinition["input"]): Co case "tag": case "dataview": case "document_block": + case "markdown_block": return []; default: return absurd(input); diff --git a/src/views/FormBuilder.svelte b/src/views/FormBuilder.svelte index 2f07473..e3c0626 100644 --- a/src/views/FormBuilder.svelte +++ b/src/views/FormBuilder.svelte @@ -353,8 +353,14 @@ bind:value={field.input.query} {app} /> - {:else if field.input.type === "document_block"} - + {:else if field.input.type === "document_block" || field.input.type === "markdown_block"} + {/if} diff --git a/src/views/components/Form/DocumentBlock.svelte b/src/views/components/Form/DocumentBlock.svelte index 919f09e..059901b 100644 --- a/src/views/components/Form/DocumentBlock.svelte +++ b/src/views/components/Form/DocumentBlock.svelte @@ -2,7 +2,7 @@ import { parseFunctionBody, pipe } from "@std"; import * as R from "fp-ts/Record"; import * as TE from "fp-ts/TaskEither"; - import { sanitizeHTMLToDom } from "obsidian"; + import { App, sanitizeHTMLToDom } from "obsidian"; import { input } from "src/core"; import { FieldValue, FormEngine } from "src/store/formStore"; import { notifyError } from "src/utils/Log"; @@ -11,7 +11,12 @@ export let form: FormEngine; export let field: input.DocumentBlock; - $: functionParsed = parseFunctionBody<[Record], string>(field.body, "form"); + export let app: App; + $: dv = app.plugins.plugins.dataview?.api; + $: functionParsed = parseFunctionBody< + [Record, unknown, HTMLElement], + string + >(field.body, "form", "dv", "el"); /* I probably... probably should better export the real type the FormEngine has rather than this mess of types... but I wanted to keep that private to the file... You can argue that I am exposing it with all tis dark magic, but at least this way it is kept in sync if the type changes? */ @@ -26,7 +31,7 @@ pipe( form.fields, R.filterMap((field) => field.value), - fn, + (fields) => fn(fields, dv, parent), ), ), TE.match( @@ -34,7 +39,7 @@ console.error(error); notifyError("Error in document block")(String(error)); }, - (newText) => parent.setText(sanitizeHTMLToDom(newText)), + (newText) => newText && parent.setText(sanitizeHTMLToDom(newText)), ), )(); return { diff --git a/src/views/components/Form/MarkdownBlock.svelte b/src/views/components/Form/MarkdownBlock.svelte new file mode 100644 index 0000000..13a55c1 --- /dev/null +++ b/src/views/components/Form/MarkdownBlock.svelte @@ -0,0 +1,61 @@ + + +
diff --git a/src/views/components/Form/RenderField.svelte b/src/views/components/Form/RenderField.svelte index 9053dc8..b6dd6a5 100644 --- a/src/views/components/Form/RenderField.svelte +++ b/src/views/components/Form/RenderField.svelte @@ -3,6 +3,7 @@ import { App } from "obsidian"; import { FieldDefinition } from "src/core/formDefinition"; import { FormEngine } from "src/store/formStore"; + import { logger as l } from "src/utils/Logger"; import InputField from "src/views/components/Form/InputField.svelte"; import ObsidianInputWrapper from "src/views/components/Form/ObsidianInputWrapper.svelte"; import { derived } from "svelte/store"; @@ -10,13 +11,13 @@ import InputDataview from "./InputDataview.svelte"; import InputFolder from "./InputFolder.svelte"; import InputNote from "./InputNote.svelte"; + import InputSlider from "./inputSlider.svelte"; import InputTag from "./InputTag.svelte"; import InputTextArea from "./InputTextArea.svelte"; + import MarkdownBlock from "./MarkdownBlock.svelte"; import MultiSelectField from "./MultiSelectField.svelte"; import ObsidianSelect from "./ObsidianSelect.svelte"; import ObsidianToggle from "./ObsidianToggle.svelte"; - import { logger as l } from "src/utils/Logger"; - import InputSlider from "./inputSlider.svelte"; export let model: ReturnType; export let definition: FieldDefinition; @@ -54,13 +55,15 @@ {:else if definition.input.type === "textarea"} + {:else if definition.input.type === "markdown_block"} + {:else if definition.input.type === "document_block"} - + {:else} - import { E, pipe, parseFunctionBody } from "@std"; + import { E, parseFunctionBody, pipe } from "@std"; import FormRow from "./FormRow.svelte"; export let body = ""; export let index: number; + export let flavour: "markdown" | "html"; $: id = "document_block_" + index; const placeholder = "return `Hello ${form.name}!`"; $: errors = pipe( @@ -18,12 +19,20 @@ - This is a document block input. It is not meant to be used as a normal - input, instead it is to render some instructions to the user. It is - expected to be a function body that returns a string. Within the - function body, you can access the form data using the form + {#if flavour === "markdown"} + This is markdown block. It is not a real input, it is used to render some markdown + inside your form. + {:else} + This is a document block input. It is not meant to be used as a normal input, instead it + is to render some instructions to the user. + {/if} + It is expected to contain a function body that returns a string. Within the function body, you + can access the form data using the form variable. For example:
{placeholder}
+

+ You also have access to the Dataview API through the dv variable. +