Template for insert callout

I use callouts from time to time, but I don’t often remember which types are possible, especially with the possibilities added by themes and plugins. So I created this template which uses templater to insert a callout by proposing the theme, the possibility of folding it or not and the title. If text is selected, it inserts it into the body of the callout.

I’ll share it if others are interested:

<%*
//get selection
noteContent = tp.file.selection();
// list callouts
const callouts = {
   note:     '🔵 ✏ Note',
   info:     '🟢 ℹ Info',
   todo:     '🟢 ✔️ Todo',
   tip:      '🌐 🔥 Tip / Hint / Important',
   abstract: '🌐 📋 Abstract / Summary / TLDR',
   question: '🟡 ❓ Question / Help / FAQ',
   quote:    '🔘 💬 Quote / Cite',
   example:  '🟣 📑 Example',
   success:  '🟢 ✔ Success / Check / Done',
   warning:  '🟠 ⚠ Warning / Caution / Attention',
   failure:  '🔴 ❌ Failure / Fail / Missing',
   danger:   '🔴 ⚡ Danger / Error',
   bug:      '🔴 🐞 Bug'
};
// return callout
const type = await tp.system.suggester(Object.values(callouts), Object.keys(callouts), true, 'Select callout type.');
//return fold
const fold = await tp.system.suggester(['None', 'Expanded', 'Collapsed'], ['', '+', '-'], true, 'Select callout fold option.');

//return title
const title = await tp.system.prompt('Title:', '', true);

//get array of lines
lines = noteContent.split('\n')
//make a new string with > prepended to each line
let newContent = "";
lines.forEach(l => {
	newContent += '> ' + l + "\n";
})
//remove the last newline character
newContent = newContent.replace(/\n$/, "");
//define callout header
header = ">[!"+type+"]"+fold + " " + title +"\n"
// Return the complete callout block
return header + newContent;
%>
19 Likes

This could be really handy! Currently, however, if I insert the templater code block into a note that already has text, and run “replace templates in the current file”, it deletes all the text, leaving only one line, such as:
>[!abstract]+ This is all that is left!

1 Like

I get what you mean. It is, however, possible using the admonitions plugin. I use it all the time. It gives you a nice shortcut that opens a menu with all callouts including custom ones defines by you.

You can fill in the name of the callout and even choose whether it should be open or closed.

For inserting this template, you have to place it in your template folder. And when you want to insert a callout in a note, you have to trigger “open insert template modal”, then select this template. Effectively , if you trigger “replace templates in the current files”, it replace all the file.
To use it more easily, you can assign it a keyboard shortcut in the templater settings.

I prefer using a template instead of the admonition plugin because it takes up less space and I easily have a lot of plugins.

Thanks! That works. I just tend to use “insert template” for all my templates, which gives me a chance to review it before I run the command to replace the variables.

In response to this:

I’ve actually never seen that happening with other Templater templates; they simply replace the variables or run actions. I’m just saying you might want to warn people about this (or change the code).

Thanks again for this!

Thanks for your advice, I will warn about this the next time I share it if it happens.
It is weird because I use and I saw a lot of template who act like mine. And I would find it weird to use it with the command “replace template”, because we want to insert something not replace something. But Everyone has their own preferences and points of view.
And I admit that I would not know how to modify it so that it can be used with this command there.

This is great, thanks for sharing the template!

1 Like

Hello, I deeply appreciate your dedication and the effort you have put into this. I have a humble request to make - would it be possible for you to kindly consider using the first line of the selected text as the title? In my usual writing process, I tend to formulate the title before delving into the main content, as I believe it aligns with a more logical thought flow. Hence, I genuinely believe that adopting this approach would greatly enhance the overall structure and coherence of the text.

Thank you once again for your invaluable assistance.

I’ve modified the Template so that the first selected line is selected as the title and removed from the body, so that the title is pre-filled.

:warning: EDIT: This template is no longer working for the moment

<%*
//get selection
noteContent = await tp.file.selection();
let titre = noteContent.match(/.*(?=\n.*)/g)[0]
let corps = noteContent.match(/(?<=.*\n)(.|\n)*/g)[0]
// list callouts
const callouts = {
   note:     '🔵 ✏ Note',
   info:     '🟢 ℹ Info',
   todo:     '🟢 ✔️ Todo',
   asidecleanright: '⚪ 💬commentaire',
   tip:      '🌐 🔥 Tip / Hint / Important',
   abstract: '🌐 📋 Abstract / Summary / TLDR',
   question: '🟡 ❓ Question / Help / FAQ',
   quote:    '🔘 💬 Quote / Cite',
   example:  '🟣 📑 Example',
   success:  '🟢 ✔ Success / Check / Done',
   warning:  '🟠 ⚠ Warning / Caution / Attention',
   failure:  '🔴 ❌ Failure / Fail / Missing',
   danger:   '🔴 ⚡ Danger / Error',
   bug:      '🔴 🐞 Bug',
   recite:   '⚪ 🎞️ recite',
   sommaire: '🟠 📋 sommaire',
   idea:     '🟡 💡 idée',
   daily:    '🔵 📆 daily',
   day:      '⚪ ✒️ day'
};
// return callout
const type = await tp.system.suggester(Object.values(callouts), Object.keys(callouts), true, 'Select callout type.');
//return fold
const fold = await tp.system.suggester(['None', 'Expanded', 'Collapsed'], ['', '+', '-'], true, 'Select callout fold option.');

//return titler
const title = await tp.system.prompt('Title:', titre , true);

//get array of lines
lines = corps.split('\n')
//make a new string with > prepended to each line
let newContent = "";
lines.forEach(l => {
	newContent += '> ' + l + "\n";
})
//remove the last newline character
newContent = newContent.replace(/\n$/, "");
//define callout header
header = "> [!"+type+"]"+fold + " " + title +"\n"
// Return the complete callout block
return header + newContent;
%>
2 Likes

oh dear, I cannot thank you enough for taking the time to assist me.

@Anwen - this is awesome! I appreciate the inline comments and your effort.

@Anwen, thanks for the great template! I took it a little further, wrote something to check how many lines were selected, and then behave accordingly. If no lines are selected, then the template title is blank, and there is no content. If there is only the title selected, then only the title will populate. Last, if there are multiple lines selected, then the top line is the title, and all others are placed in the contents. I just did some quick testing, and I think it works well for all cases, but please let me know if there is a bug!

<%*
//get selection
noteContent = await tp.file.selection();

// Check if the selected text has one or two strings
let numberOfStrings = noteContent.split('\n').length;
let titre;
let corps;

if (numberOfStrings === 1) {
  // Ingest titre only
  titre = noteContent.match(/.*/g)[0];
  corps = "";
} else if (numberOfStrings > 1) {
  // Ingest titre and corps
  titre = noteContent.match(/.*(?=\n.*)/g)[0];
  corps = noteContent.match(/(?<=.*\n)(.|\n)*/g).join('\n');
}
console.log(corps);
// list callouts
const callouts = {
   note:     '🔵 ✏ Note',
   info:     '🟢 ℹ Info',
   todo:     '🟢 ✔️ Todo',
   asidecleanright: '⚪ 💬commentaire',
   tip:      '🌐 🔥 Tip / Hint / Important',
   abstract: '🌐 📋 Abstract / Summary / TLDR',
   question: '🟡 ❓ Question / Help / FAQ',
   quote:    '🔘 💬 Quote / Cite',
   example:  '🟣 📑 Example',
   success:  '🟢 ✔ Success / Check / Done',
   warning:  '🟠 ⚠ Warning / Caution / Attention',
   failure:  '🔴 ❌ Failure / Fail / Missing',
   danger:   '🔴 ⚡ Danger / Error',
   bug:      '🔴 🐞 Bug',
   recite:   '⚪ 🎞️ recite',
   sommaire: '🟠 📋 sommaire',
   idea:     '🟡 💡 idée',
   daily:    '🔵 📆 daily',
   day:      '⚪ ✒️ day'
};
// return callout
const type = await tp.system.suggester(Object.values(callouts), Object.keys(callouts), true, 'Select callout type.');
//return fold
const fold = await tp.system.suggester(['None', 'Expanded', 'Collapsed'], ['', '+', '-'], true, 'Select callout fold option.');

//return titler
const title = await tp.system.prompt('Title:', titre , true);

//get array of lines
lines = corps.split('\n');
//make a new string with > prepended to each line
let newContent = "";
lines.forEach(l => {
	newContent += '> ' + l + "\n";
})
//remove the last newline character
newContent = newContent.replace(/\n$/, "");
//define callout header
header = "> [!"+type+"]"+fold + " " + title +"\n";
// Return the complete callout block
return header + newContent;
%>
3 Likes

hello, I notice there are some custom callout
recite: ‘:white_circle: :film_strip: recite’,
sommaire: ‘:orange_circle: :clipboard: sommaire’,
idea: ‘:yellow_circle: :bulb: idée’,
daily: ‘:large_blue_circle: :calendar: daily’,
day: ‘:white_circle: :black_nib: day’
Do you mind if I ask about the sources of these CSS

The recite callout comes from the snippet callout adjustement which I believe comes from the creator of ITS theme.

/* Recite */
.callout.callout[data-callout=recite] {
  --callout-color: 193, 67, 67;
  --callout-icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path stroke="none" fill="none" d="M0 0h24v24H0z"/><path d="M6.455 19L2 22.5V4a1 1 0 0 1 1-1h18a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H6.455z"/></svg>';
  padding: 10px;
  padding-top: 5px;
  margin: 10px;
  border-style: solid;
  border-width: 11px;
  border-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAA8CAYAAADxJz2MAAAFWWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS41LjAiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICAgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iCiAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIKICAgIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIKICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgZXhpZjpQaXhlbFhEaW1lbnNpb249IjgwIgogICBleGlmOlBpeGVsWURpbWVuc2lvbj0iNjAiCiAgIGV4aWY6Q29sb3JTcGFjZT0iMSIKICAgdGlmZjpJbWFnZVdpZHRoPSI4MCIKICAgdGlmZjpJbWFnZUxlbmd0aD0iNjAiCiAgIHRpZmY6UmVzb2x1dGlvblVuaXQ9IjIiCiAgIHRpZmY6WFJlc29sdXRpb249IjMwMC8xIgogICB0aWZmOllSZXNvbHV0aW9uPSIzMDAvMSIKICAgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIKICAgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9InNSR0IgSUVDNjE5NjYtMi4xIgogICB4bXA6TW9kaWZ5RGF0ZT0iMjAyMi0wMS0wMlQxNjowNTo0MS0wODowMCIKICAgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyMi0wMS0wMlQxNjowNTo0MS0wODowMCI+CiAgIDxkYzp0aXRsZT4KICAgIDxyZGY6QWx0PgogICAgIDxyZGY6bGkgeG1sOmxhbmc9IngtZGVmYXVsdCI+RCZhbXA7RCBCb3JkZXI8L3JkZjpsaT4KICAgIDwvcmRmOkFsdD4KICAgPC9kYzp0aXRsZT4KICAgPHhtcE1NOkhpc3Rvcnk+CiAgICA8cmRmOlNlcT4KICAgICA8cmRmOmxpCiAgICAgIHN0RXZ0OmFjdGlvbj0icHJvZHVjZWQiCiAgICAgIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFmZmluaXR5IERlc2lnbmVyIDEuMTAuNCIKICAgICAgc3RFdnQ6d2hlbj0iMjAyMi0wMS0wMlQxNjowNTo0MS0wODowMCIvPgogICAgPC9yZGY6U2VxPgogICA8L3htcE1NOkhpc3Rvcnk+CiAgPC9yZGY6RGVzY3JpcHRpb24+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgo8P3hwYWNrZXQgZW5kPSJyIj8+SLcLyAAAAYFpQ0NQc1JHQiBJRUM2MTk2Ni0yLjEAACiRdZHPK0RRFMc/8xD50SiUhcVLWA35UWJjMZNfhcXMKIPNm2fejJo3Xu+NJFtlO0WJjV8L/gK2ylopIiVLWRMbpuc8o0Yy53bP/dzvPed077mgRNO66ZR3g5nJ2uHRoDoTm1Urn/Ch0EQdqqY71mRkJEpJe7+VaLHrTq9W6bh/rWYh4ejgqxIe0i07KzwmPLGStTzeEm7UU9qC8IlwwJYLCt94erzAzx4nC/zpsR0Nh0CpF1aTvzj+i/WUbQrLy2kz08v6z328l9QmMtMRWVtltuAQZpQgKuMME6KfHgbF99NJL12yo0R+93f+FEuSq4u3WMVmkSQpsgREXZbqCVkN0RMy0qx6/f/bV8fo6y1Urw1CxaPrvrZD5Sbkc677ceC6+UMoe4DzTDF/aR8G3kTPFbW2PfCvw+lFUYtvw9kGNN9bmq19S2UyFcOAl2Ooi0HDFVTPFXr2c87RHUTX5KsuYWcXOiTeP/8FK5Jny8RYHqYAAAAJcEhZcwAALiMAAC4jAXilP3YAAAG5SURBVHic7dyxSiNRFMbxv0OwEkvZfrEWleWAvbA+giB5ANtgcx/gFJK0+wAbwUdYV7bZRjiIirXYL1tbiajFXHV3Y5KBbIyTfL8yOQxfPu5kprkXKnCzRTfrVpmdBm7WdbPFKrNFhYt9As6BnVGD1cgOcJ5/+0CNfl+4WQG0AB80N8U+AiduloBOirh/bejVFehmH4AjYJ/ZLO9Jg7KDo9xJj54C3ewzcAlsjjdbrWwCl7mbvzyvLjebp7xdW28YrE6WgG9u1gFSiriFvALdbBk4QeVV0aL8b1wGKNysCVwA6xONVS/rwIWbNefc7GHSaeps6HugiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIyCzQTqURaafSiBpAE/gCLAwbThFzY0/0DlS8K2+A3SJFdIE14Gy8sabKGbCWIroFQIq4AjaA9kRj1UMb2MidvexYzzuw99zsB/CVcoe2vPgNNFPE9z8/7HmI5IEV4PiNgtXBMbDyb3nQ5ymcIn4BW8AecDfebO/aHWUHW7mTHn2PNMnnpLTd7CdwSHmOyiy5BrZTxOmgoaHvgfkCq8DBfwpWBwfA6rDyAB4BTjVxWZByO0gAAAAASUVORK5CYII=") 11;
  border-image-outset: 9px 0px;
  box-shadow: 0px 0px 10px var(--outline, var(--background-modifier-box-shadow));
  background: var(--note, var(--background-primary));
  text-align: justify;
}
.callout.callout[data-callout=recite] .callout-title {
  padding: 0;
  background: transparent;
  color: rgba(var(--callout-color), 1);
  justify-content: center;
}
.callout.callout[data-callout=recite][data-callout-metadata*=bg-]:not([data-callout-metadata*=bg-c]) .callout-title {
  color: var(--text-normal);
}
.callout.callout[data-callout=recite] .callout-title-inner {
  flex: unset;
}
.callout.callout[data-callout=recite] .callout-content {
  padding: 0;
  padding-top: 10px;
}

For the others, I don’t think I use them anymore, and I can’t find where they came from, I think I have deleted the css, sorry.

But for the note I use a custom svg with this:

.callout[data-callout = "note"] {
    --callout-color: 26, 140, 216;
    --callout-icon: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs/><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="1" d="M0 0h512M0 0h512m0 0v512m0-512v512m0 0H0m512 0H0m0 0V0m0 512V0"/><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="8" d="M112 40h256m-256 0h256m0 0c21.33 0 32 10.67 32 32m-32-32c21.33 0 32 10.67 32 32m0 0v367.74M400 72v367.74m0 0c0 21.33-10.67 32-32 32m32-32c0 21.33-10.67 32-32 32m0 0H112m256 0H112m0 0c-21.33 0-32-10.67-32-32m32 32c-21.33 0-32-10.67-32-32m0 0V72m0 367.74V72m0 0c0-21.33 10.67-32 32-32M80 72c0-21.33 10.67-32 32-32M100 221.628c46.27-.27 231.34-1.36 277.61-1.63M100 221.628c46.27-.27 231.34-1.36 277.61-1.63M100 301.628c46.27-.27 231.34-1.36 277.61-1.63M100 301.628c46.27-.27 231.34-1.36 277.61-1.63M100 381.628c46.27-.27 231.34-1.36 277.61-1.63M100 381.628c46.27-.27 231.34-1.36 277.61-1.63M100 141.628c46.27-.27 231.34-1.36 277.61-1.63M100 141.628c46.27-.27 231.34-1.36 277.61-1.63"/></svg>;
}

how can you add custom callouts? because it keeps on giving me an error

When It give you an error ? What is the error ?
I add custom callout by css snippet. And in my template, I add the new callout in the callout list, with this syntax : callout-name: 'informations about this callout', . Make sure there is a comma between the different callouts but not at the end.

do the callouts have to be separate css files? cause i have them in one big file
and the error is "template parsing error "

So, the error is not causing by the css snippets. Can you copy your template here , or capture a screenshot of your template ? There must be a syntax error.

<%*
//get selection
noteContent = await tp.file.selection();
let titre = noteContent.match(/.(?=\n.)/g)[0]
let corps = noteContent.match(/(?<=.\n)(.|\n)/g)[0]
// list callouts
const callouts = {
note: ‘:large_blue_circle: :pencil2: Note’,
info: ‘:green_circle: :information_source: Info’,
todo: ‘:green_circle: :heavy_check_mark: Todo’,
asidecleanright: ‘:white_circle: :speech_balloon:commentaire’,
tip: ’ :fire: Tip / Hint / Important’,
abstract: ’ :clipboard: Abstract / Summary / TLDR’,
question: ’ :question: Question / Help / FAQ’,
quote: ’ :speech_balloon: Quote / Cite’,
example: ’ :bookmark_tabs: Example’,
success: ’ :heavy_check_mark: Success / Check / Done’,
warning: ’ :warning: Warning / Caution / Attention’,
failure: ’ :x: Failure / Fail / Missing’,
danger: ’ :zap: Danger / Error’,
bug: ’ :lady_beetle: Bug’,
resources: ‘resources’,
code: ‘code’,
code2: ‘code version 2’,
proof: ‘transparent callout’
};
// return callout
const type = await tp.system.suggester(Object.values(callouts), Object.keys(callouts), true, ‘Select callout type.’);
//return fold
const fold = await tp.system.suggester([‘None’, ‘Expanded’, ‘Collapsed’], [‘’, ‘+’, ‘-’], true, ‘Select callout fold option.’);

//return titler
const title = await tp.system.prompt(‘Title:’, titre , true);

//get array of lines
lines = corps.split(‘\n’)
//make a new string with > prepended to each line
let newContent = “”;
lines.forEach(l => {
newContent += '> ’ + l + “\n”;
})
//remove the last newline character
newContent = newContent.replace(/\n$/, “”);
//define callout header
header = “> [!”+type+“]”+fold + " " + title +“\n”
// Return the complete callout block
return header + newContent;
%>

Ok. So, my second template with the title preinserted is no longer working. You can use this written by @lancew instead of my template :

<%*
//get selection
noteContent = await tp.file.selection();

// Check if the selected text has one or two strings
let numberOfStrings = noteContent.split('\n').length;
let titre;
let corps;

if (numberOfStrings === 1) {
  // Ingest titre only
  titre = noteContent.match(/.*/g)[0];
  corps = "";
} else if (numberOfStrings > 1) {
  // Ingest titre and corps
  titre = noteContent.match(/.*(?=\n.*)/g)[0];
  corps = noteContent.match(/(?<=.*\n)(.|\n)*/g).join('\n');
}
console.log(corps);
// list callouts
const callouts = {
   note:     '🔵 ✏ Note',
   info:     '🟢 ℹ Info',
   todo:     '🟢 ✔️ Todo',
   asidecleanright: '⚪ 💬commentaire',
   tip:      '🌐 🔥 Tip / Hint / Important',
   abstract: '🌐 📋 Abstract / Summary / TLDR',
   question: '🟡 ❓ Question / Help / FAQ',
   quote:    '🔘 💬 Quote / Cite',
   example:  '🟣 📑 Example',
   success:  '🟢 ✔ Success / Check / Done',
   warning:  '🟠 ⚠ Warning / Caution / Attention',
   failure:  '🔴 ❌ Failure / Fail / Missing',
   danger:   '🔴 ⚡ Danger / Error',
   resources: 'resources',
   code: 'code',
   code2: 'code version 2',
   proof: 'transparent callout'	
};
// return callout
const type = await tp.system.suggester(Object.values(callouts), Object.keys(callouts), true, 'Select callout type.');
//return fold
const fold = await tp.system.suggester(['None', 'Expanded', 'Collapsed'], ['', '+', '-'], true, 'Select callout fold option.');

//return titler
const title = await tp.system.prompt('Title:', titre , true);

//get array of lines
lines = corps.split('\n');
//make a new string with > prepended to each line
let newContent = "";
lines.forEach(l => {
	newContent += '> ' + l + "\n";
})
//remove the last newline character
newContent = newContent.replace(/\n$/, "");
//define callout header
header = "> [!"+type+"]"+fold + " " + title +"\n";
// Return the complete callout block
return header + newContent;
%>
4 Likes