diff --git a/src/docs.ts b/src/docs.ts
index 277d8ec9..04f1d071 100644
--- a/src/docs.ts
+++ b/src/docs.ts
@@ -17,6 +17,7 @@ export const DOCS_BASE_URL = "https://quickadd.obsidian.guide";
export const DOCS_URLS = {
gettingStarted: `${DOCS_BASE_URL}/docs/`,
+ formatSyntax: `${DOCS_BASE_URL}/docs/FormatSyntax/`,
onePageInputs: `${DOCS_BASE_URL}/docs/Advanced/onePageInputs/`,
userScripts: `${DOCS_BASE_URL}/docs/Choices/MacroChoice/#user-scripts`,
packages: `${DOCS_BASE_URL}/docs/Choices/Packages/`,
diff --git a/src/gui/ChoiceBuilder/CaptureChoiceForm.svelte b/src/gui/ChoiceBuilder/CaptureChoiceForm.svelte
index 16590adc..3a577a3b 100644
--- a/src/gui/ChoiceBuilder/CaptureChoiceForm.svelte
+++ b/src/gui/ChoiceBuilder/CaptureChoiceForm.svelte
@@ -12,6 +12,7 @@ import ChoiceNameHeader from "./components/ChoiceNameHeader.svelte";
import ValidatedInput from "./components/ValidatedInput.svelte";
import LabeledField from "./components/LabeledField.svelte";
import FormatPreviewField from "./components/FormatPreviewField.svelte";
+import FormatTokenHint from "./components/FormatTokenHint.svelte";
import AppendLinkSetting from "./components/AppendLinkSetting.svelte";
import OpenFileSetting from "./components/OpenFileSetting.svelte";
import FileOpeningSetting from "./components/FileOpeningSetting.svelte";
@@ -170,6 +171,7 @@ function onTemplaterAfterCaptureChange(value: boolean) {
requiredMessage="Capture format is required when enabled"
makeSuggesters={formatSuggesters}
/>
+
{/snippet}
diff --git a/src/gui/ChoiceBuilder/TemplateChoiceForm.svelte b/src/gui/ChoiceBuilder/TemplateChoiceForm.svelte
index aee1ebc6..44f5867f 100644
--- a/src/gui/ChoiceBuilder/TemplateChoiceForm.svelte
+++ b/src/gui/ChoiceBuilder/TemplateChoiceForm.svelte
@@ -34,6 +34,7 @@ import ChoiceNameHeader from "./components/ChoiceNameHeader.svelte";
import ValidatedInput from "./components/ValidatedInput.svelte";
import LabeledField from "./components/LabeledField.svelte";
import FormatPreviewField from "./components/FormatPreviewField.svelte";
+import FormatTokenHint from "./components/FormatTokenHint.svelte";
import AppendLinkSetting from "./components/AppendLinkSetting.svelte";
import OpenFileSetting from "./components/OpenFileSetting.svelte";
import FileOpeningSetting from "./components/FileOpeningSetting.svelte";
@@ -222,6 +223,7 @@ function onModeChange(value: string) {
placeholder="File name format"
makeSuggesters={fileNameSuggesters}
/>
+
+
{#if !usesPickerTargetSyntax}
{/if}
diff --git a/src/gui/ChoiceBuilder/components/FormatTokenHint.svelte b/src/gui/ChoiceBuilder/components/FormatTokenHint.svelte
new file mode 100644
index 00000000..528f110a
--- /dev/null
+++ b/src/gui/ChoiceBuilder/components/FormatTokenHint.svelte
@@ -0,0 +1,35 @@
+
+
+{#if shown}
+
+{/if}
diff --git a/src/gui/ChoiceBuilder/components/FormatTokenHint.test.ts b/src/gui/ChoiceBuilder/components/FormatTokenHint.test.ts
new file mode 100644
index 00000000..373cd6a0
--- /dev/null
+++ b/src/gui/ChoiceBuilder/components/FormatTokenHint.test.ts
@@ -0,0 +1,52 @@
+import { describe, expect, it } from "vitest";
+import { render } from "@testing-library/svelte";
+import { tick } from "svelte";
+import FormatTokenHint from "./FormatTokenHint.svelte";
+import { DOCS_URLS } from "../../../docs";
+
+const hint = (container: HTMLElement) =>
+ container.querySelector(".qa-token-hint");
+
+/**
+ * Issue #1542, ask 1. The token autocomplete opens on `{{` and nothing said so.
+ */
+describe("FormatTokenHint", () => {
+ it("names the two characters that open the autocomplete", async () => {
+ const { container } = render(FormatTokenHint, { props: { value: "" } });
+ await tick();
+
+ const text = hint(container as HTMLElement)?.textContent ?? "";
+ expect(text).toContain("{{");
+ expect(text).toContain("to insert a token");
+ });
+
+ it("links the format syntax reference", async () => {
+ const { container } = render(FormatTokenHint, { props: { value: "" } });
+ await tick();
+
+ const link = container.querySelector("a.quickadd-docs-link");
+ expect(link?.getAttribute("href")).toBe(DOCS_URLS.formatSyntax);
+ expect(link?.getAttribute("target")).toBe("_blank");
+ expect(link?.getAttribute("rel")).toBe("noopener noreferrer");
+ });
+
+ it("stays out of the way once the field uses a token", async () => {
+ const { container } = render(FormatTokenHint, {
+ props: { value: "- [ ] {{VALUE}}" },
+ });
+ await tick();
+ expect(hint(container as HTMLElement)).toBeNull();
+ });
+
+ it("shows again if the user removes every token", async () => {
+ const { container, rerender } = render(FormatTokenHint, {
+ props: { value: "{{DATE}}" },
+ });
+ await tick();
+ expect(hint(container as HTMLElement)).toBeNull();
+
+ await rerender({ value: "plain text" });
+ await tick();
+ expect(hint(container as HTMLElement)).not.toBeNull();
+ });
+});
diff --git a/src/styles.css b/src/styles.css
index 855e159e..80cd0cfb 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -232,6 +232,19 @@
border: 0;
}
+/* "Type {{ to insert a token" under a format field (#1542). A quiet secondary
+ line, matching .qa-preview-row: it is a teaching aid, not part of the field. */
+.quickAddModal .qa-token-hint {
+ margin: -4px 0 8px;
+ font-size: var(--font-ui-smaller);
+ color: var(--text-muted);
+}
+.quickAddModal .qa-token-hint code {
+ font-size: inherit;
+ padding: 1px 4px;
+ border-radius: var(--radius-s, 4px);
+}
+
/* Problems the preview pass ran into, shown here instead of as a Notice per
keystroke (#1558). Colour carries severity — no glyph — matching
.qa-folder-mode-warning. Clamped with the full text in `title`, because the