[BETA] Supertag

name

Supertag

description

Tana like supertags inside of amplenote! testing version.

NOTE: THE PLUGIN IS NOT FEATURE COMPLETE YET, IT'S A BETA VERSION

How to use

1. Install the extension then create a tag note
2. Link the note with other notes by doing @<tag/note name> on the sentence that you want to have tagged
3. Run the plugin from note options that will add an embed to the note

{
constants: {},
 
noteOption: {
Embed: {
check: async () => true,
 
run: async (app, noteUUID) => {
try {
await app.insertNoteContent(
{ uuid: noteUUID },
`<object
data="plugin://${app.context.pluginUUID}?${noteUUID}"
data-aspect-ratio="1"
style="width:100%; height:400px; border:0;"
></object>`,
);
} catch (err) {
console.error("Failed to insert embed:", err);
await app.alert("Error inserting embed.");
}
},
},
},
 
async renderEmbed(app, noteUUID) {
await this._loadScript("https://unpkg.com/snarkdown/dist/snarkdown.umd.js");
await this._loadScript(
"https://cdnjs.cloudflare.com/ajax/libs/pell/1.0.6/pell.min.js",
);
 
try {
const targetNoteHandle = { uuid: noteUUID };
const sourceNoteHandles = await app.getNoteBacklinks(targetNoteHandle); // Gets all uuids that have referenced the target note
 
if (!sourceNoteHandles?.length) {
return this._renderHtml("Tana Tags", "<p>No backlinks found.</p>");
}
 
const tableRows = [];
const tableCols = new Set();
 
for (const sourceNoteHandle of sourceNoteHandles) {
try {
const backlinkContents = await app.getNoteBacklinkContents(
targetNoteHandle,
sourceNoteHandle,
);
 
// For loop cuz if a sinle note has multiple backlinks backlinkContents will be an array
for (const backlinkContent of backlinkContents) {
// Regex to extract the column entries that are stroed in the richfootnote of the tag link in markdown
const regex = /(?<=\]\:.*?\n\s+).+/;
const match = backlinkContent.match(regex);
const extractedContent = match ? match[0].trim() : null;
 
let jsonObject = null;
if (extractedContent) {
try {
jsonObject = JSON.parse(extractedContent);
} catch (e) {
console.error("Failed to parse JSON:", e);
}
}
 
// Create a string for the additional table data cells
let dataCells = "";
if (jsonObject) {
for (const key in jsonObject) {
if (Object.hasOwnProperty.call(jsonObject, key)) {
dataCells += `<td>${jsonObject[key]}</td>`;
tableCols.add(key);
}
}
}
 
tableRows.push(`
<tr>
<td><a href="note://amplenote.com/notes/${sourceNoteHandle.uuid}">URL</a></td>
<td>${snarkdown(backlinkContent) || "(empty)"}</td>
${dataCells}
</tr>
`);
}
} catch (err) {
console.warn("Error loading backlink contents:", err);
}
}
 
let colHeadingHtml = "";
for (const column of tableCols) {
colHeadingHtml += `<th>${column}</th>`;
}
 
const tableHtml = `
<table border="1" cellspacing="0" cellpadding="6">
<thead>
<tr>
<th>Source Note</th>
<th>Content</th>
${colHeadingHtml}
</tr>
</thead>
<tbody>
${tableRows.join("")}
</tbody>
</table>
`;
 
return this._renderHtml("Tana Tags", tableHtml);
} catch (err) {
console.error("Error rendering embed:", err);
return this._renderHtml("Tana Tags", "<p>Error loading backlinks.</p>");
}
},
 
_renderHtml(title, bodyContent) {
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>${title}</title>
<style>
body {
font-family: sans-serif;
background: #1e1e1e;
color: #e0e0e0;
overflow: auto;
padding: 1rem;
}
 
table {
border-collapse: collapse;
width: 100%;
background: #2a2a2a;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 0 10px rgba(0,0,0,0.5);
}
 
th, td {
border: 1px solid #3a3a3a;
padding: 10px 12px;
text-align: left;
}
 
th {
background: #333;
color: #ffcc66; /* gold accent */
font-weight: 600;
}
 
tr:nth-child(even) {
background: #252525;
}
 
tr:hover {
background: #3a3a3a;
}
 
a {
color: #66aaff;
text-decoration: none;
}
 
a:hover {
text-decoration: underline;
}
 
</style>
</head>
<body>
<h1>${title}</h1>
${bodyContent}
</body>
</html>
`;
},
 
async _loadScript(url) {
return new Promise((resolve, reject) => {
const script = document.createElement("script");
script.src = url;
script.onload = resolve;
script.onerror = () => reject(new Error(`Failed to load script: ${url}`));
document.head.appendChild(script);
});
},
}