Skip to content

Commit

Permalink
Merge pull request #356 from danielo515/feat/templater-in-templates
Browse files Browse the repository at this point in the history
Feat/templater-in-templates
  • Loading branch information
danielo515 authored Dec 18, 2024
2 parents f75b1e4 + 4b90dd2 commit fa213c0
Show file tree
Hide file tree
Showing 12 changed files with 434 additions and 32 deletions.
3 changes: 2 additions & 1 deletion EXAMPLE_VAULT/.obsidian/app.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"alwaysUpdateLinks": true,
"attachmentFolderPath": "attachments"
"attachmentFolderPath": "attachments",
"promptDelete": false
}
6 changes: 3 additions & 3 deletions EXAMPLE_VAULT/.obsidian/core-plugins.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
"properties": false,
"page-preview": true,
"daily-notes": false,
"templates": false,
"templates": true,
"note-composer": true,
"command-palette": true,
"slash-command": false,
"editor-status": true,
"bookmarks": true,
"bookmarks": false,
"markdown-importer": false,
"zk-prefixer": false,
"random-note": false,
Expand All @@ -24,7 +24,7 @@
"slides": false,
"audio-recorder": false,
"workspaces": false,
"file-recovery": true,
"file-recovery": false,
"publish": false,
"sync": false
}
196 changes: 196 additions & 0 deletions EXAMPLE_VAULT/.obsidian/plugins/modal-form/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,202 @@
}
],
"version": "1"
},
{
"title": "Templater example",
"name": "templater-example",
"fields": [
{
"name": "name",
"label": "",
"description": "",
"isRequired": true,
"input": {
"type": "text",
"hidden": false
}
},
{
"name": "age",
"label": "",
"description": "",
"isRequired": false,
"input": {
"type": "number",
"hidden": false
}
},
{
"name": "favorite_book",
"label": "",
"description": "",
"isRequired": false,
"input": {
"type": "note",
"folder": "Books"
}
},
{
"name": "isFamily",
"label": "",
"description": "",
"isRequired": false,
"input": {
"type": "toggle",
"hidden": false
}
},
{
"name": "additional_information",
"label": "Additional info",
"description": "Provide any extra notes about this contact that you want",
"isRequired": false,
"input": {
"type": "textarea",
"hidden": false
}
},
{
"name": "dateOfBirth",
"label": "",
"description": "",
"isRequired": false,
"input": {
"type": "date",
"hidden": false
}
}
],
"version": "1",
"template": {
"parsedTemplate": [
{
"_tag": "text",
"value": "---\ncreated: <% tp.date.now(\"YYYY-MM-DD HH:mm:ss\") %>\nmodified: <% tp.file.last_modified_date(\"YYYY-MM-DD HH:mm:ss\") %>\nname: "
},
{
"_tag": "variable",
"value": "name"
},
{
"_tag": "text",
"value": "\nage: "
},
{
"_tag": "variable",
"value": "age"
},
{
"_tag": "text",
"value": "\ndateOfBirth: "
},
{
"_tag": "variable",
"value": "dateOfBirth"
},
{
"_tag": "text",
"value": "\nisFamily: "
},
{
"_tag": "variable",
"value": "isFamily"
},
{
"_tag": "text",
"value": "\nfavoriteBook: "
},
{
"_tag": "variable",
"value": "favorite_book"
},
{
"_tag": "text",
"value": "\ntags: "
},
{
"_tag": "variable",
"value": "Tags"
},
{
"_tag": "text",
"value": "\n---\n\n<%*\n// Get current time in user's timezone\nconst now = moment();\nconst age = parseInt("
},
{
"_tag": "variable",
"value": "age"
},
{
"_tag": "text",
"value": ");\nconst birthYear = now.year() - age;\nconst dateOfBirth = moment("
},
{
"_tag": "variable",
"value": "dateOfBirth"
},
{
"_tag": "text",
"value": ")\n_%>\n\n# "
},
{
"_tag": "variable",
"value": "name"
},
{
"_tag": "text",
"value": "'s Profile\n> Created on <% tp.date.now(\"dddd, MMMM Do YYYY\") %> at <% tp.date.now(\"HH:mm\") %>\n\n## Basic Information\n- **Age**: "
},
{
"_tag": "variable",
"value": "age"
},
{
"_tag": "text",
"value": " years old *(born around <%* tR += birthYear %>)*\n- **Date of Birth**: "
},
{
"_tag": "variable",
"value": "dateOfBirth"
},
{
"_tag": "text",
"value": "\n- **Family Member**: "
},
{
"_tag": "variable",
"value": "is_family"
},
{
"_tag": "text",
"value": "\n- **Days until next birthday**: <%* \nif (dateOfBirth) {\n const nextBirthday = dateOfBirth.year(now.year());\n if (nextBirthday.isBefore(now)) {\n nextBirthday.add(1, 'year');\n }\n tR += nextBirthday.diff(now, 'days');\n} else {\n tR += \"Unknown\";\n}\n\nconsole.log({ age, birthYear, frontmatter: tp.frontmatter, dateOfBirth })\n_%> days\n\n## Preferences\n- **Favorite Book**: [["
},
{
"_tag": "variable",
"value": "favorite_book"
},
{
"_tag": "text",
"value": "]]\n<%* if (tp.frontmatter.favorite_book) { %>\n> [!note] Related Books\n> ```dataview\n> LIST\n> FROM #book\n> WHERE contains(file.outlinks, [["
},
{
"_tag": "variable",
"value": "favorite_book"
},
{
"_tag": "text",
"value": "]])\n> SORT file.name ASC\n> ```\n<%* } %>\n\n## Additional Information\n"
},
{
"_tag": "variable",
"value": "additional_information"
},
{
"_tag": "text",
"value": "\n\n---\n> Last modified: <% tp.file.last_modified_date(\"dddd, MMMM Do YYYY HH:mm:ss\") %>"
}
],
"createCommand": true
}
}
]
}
36 changes: 36 additions & 0 deletions src/core/template/BasicTemplateService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { TE } from "@std";
import { App, normalizePath, TFile } from "obsidian";
import { Logger } from "src/utils/Logger";
import { TemplateError } from "./TemplateError";
import { TemplateService } from "./TemplateService";

/**
* Basic template service that creates notes with unchanged content
*/
export class BasicTemplateService implements TemplateService {
constructor(
private app: App,
private logger: Logger,
) {}

createNoteFromTemplate = (
templateContent: string,
targetFolder: string,
filename: string,
openNewNote: boolean,
): TE.TaskEither<TemplateError, void> =>
TE.tryCatch(async () => {
const fullPath = normalizePath(`${targetFolder}/${filename}.md`);
await this.app.vault.create(fullPath, templateContent);
if (openNewNote) {
const file = this.app.vault.getAbstractFileByPath(fullPath);
if (!file) {
this.logger.error("File not found", fullPath);
return;
}
if (file instanceof TFile) {
await this.app.workspace.getLeaf("split").openFile(file);
}
}
}, TemplateError.of("Error creating note from template"));
}
14 changes: 14 additions & 0 deletions src/core/template/TemplateError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export class TemplateError extends Error {
public readonly _tag = "TemplateError";
constructor(
message: string,
public readonly cause?: unknown,
) {
super(message);
this.name = "TemplateError";
}

static of(message: string) {
return (cause: unknown) => new TemplateError(message, cause);
}
}
14 changes: 14 additions & 0 deletions src/core/template/TemplateService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { TE } from "@std";
import { TemplateError } from "./TemplateError";

export interface TemplateService {
/**
* Creates a note from a template content
*/
createNoteFromTemplate(
templateContent: string,
targetFolder: string,
filename: string,
openNewNote: boolean,
): TE.TaskEither<TemplateError, void>;
}
50 changes: 50 additions & 0 deletions src/core/template/TemplaterService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { TE } from "@std";
import { App } from "obsidian";
import { Logger } from "src/utils/Logger";
import { TemplateError } from "./TemplateError";
import { TemplateService } from "./TemplateService";

export interface TemplaterApi {
create_new_note_from_template: (
content: string,
folder: string,
title: string,
openNewNote: boolean,
) => Promise<void>;
}

/**
* Template service that uses the Templater plugin
*/
export class TemplaterService implements TemplateService {
constructor(
private app: App,
private logger: Logger,
private templaterApi: TemplaterApi,
) {}

createNoteFromTemplate = (
templateContent: string,
targetFolder: string,
filename: string,
openNewNote: boolean,
): TE.TaskEither<TemplateError, void> =>
TE.tryCatch(
async () => {
const title = filename;
const result = await this.templaterApi.create_new_note_from_template(
templateContent,
targetFolder,
title,
openNewNote,
);
if (result === undefined) {
throw new Error("Templater API returned undefined, probably a parsing error");
}
},
(e) =>
e instanceof Error
? TemplateError.of(e.message)(e)
: TemplateError.of("Unknown error")(e),
);
}
16 changes: 16 additions & 0 deletions src/core/template/getTemplateService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { App } from "obsidian";
import { Logger } from "src/utils/Logger";
import { BasicTemplateService } from "./BasicTemplateService";
import { TemplaterService } from "./TemplaterService";
import { TemplateService } from "./TemplateService";

export function getTemplateService(app: App, logger: Logger): TemplateService {
const templaterApi = app.plugins.plugins["templater-obsidian"]?.templater;
if (templaterApi) {
logger.debug("Using Templater plugin for templates");
return new TemplaterService(app, logger, templaterApi);
}

logger.debug("Using basic template service");
return new BasicTemplateService(app, logger);
}
5 changes: 5 additions & 0 deletions src/core/template/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from "./TemplateService";
export * from "./TemplateError";
export * from "./BasicTemplateService";
export * from "./TemplaterService";
export * from "./getTemplateService";
Loading

0 comments on commit fa213c0

Please sign in to comment.