Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save FeralFlora/78f494c1862ce4457cef28d9d9ba5a01 to your computer and use it in GitHub Desktop.
Save FeralFlora/78f494c1862ce4457cef28d9d9ba5a01 to your computer and use it in GitHub Desktop.
Zotero import template for the Zotero integration plugin for Obsidian. Screenshots and usage guide over in the Obsidian forum here: https://forum.obsidian.md/t/zotero-integration-import-templates/36310/105?u=feralflora
  • ZI-main.md
    • The main Zotero Integration template
  • runImport.md
    • Template that enables updating literature notes at the click of a button, and much more.
  • Meta bind button template
    • Template for in-note button that executes runImport.md

The Buttons plugin is likely to be deprecated, and the maintainer (@shabegom) is urging users to migrated to Meta Bind and it's implementation of buttons. See mProjectsCode/obsidian-meta-bind-plugin#199. Therefore, I've switched out the old "Buttons" button to a Meta bind button that does the same thing.

Here's how to make it functional:

If you had set up the old "Buttons" button, you can skip steps 2, 3 & 4.

  1. If you haven't, install Meta Bind and Templater.
  2. Make sure you have the "runImport" Templater template in your vault (also found under this gist).
  3. In the runImport.md template, replace 'IMPORT_NAME' with the name you've given the Import format you want Zotero Integration to run, when importing your literature notes.

Warning

You need the name of the Import Format in Zotero Integration's settings, NOT the file name of your literature note template. See the example below.

For example, below here, the import name is "APA Literature Note", and that's what you should use.

image

  1. Associate the runImport template with a hotkey / command in Templater's settings under "Template hotkeys".
  2. Copy everything inside the "button" code block below (without the code block itself).
  3. Paste the code into an editor, and replace the path on the last line with the path to runImport inside your vault.
  4. Copy your newly edited button template, with the path corrected.
  5. Open Meta bind's settings.
  6. Find "Button templates" and press "Edit templates".
  7. At the bottom of the popup, press the button that says "Add Template from Clipboard".
  8. Then, remember to press save before you exit the "Edit templates" menu.

Button template

label: Update literature note
hidden: false
tooltip: "This will fetch new annotations from Zotero"
id: update-litnote
style: primary
actions:
  - type: command
    command: templater-obsidian:07 - Bins/Templates/Zotero Integration/runImport.md

Remember to replace path in the last line. The path starts at "07".

<%* // Get citekey from 'citekey' property, or alias starting with '@' or file name const citekey = tp.frontmatter?.citekey || tp.frontmatter.aliases?.find(alias => alias.startsWith('@')) || tp.file.title; // Get the library ID from the properties. Fall back to "My Library" (1), if the library ID is not accessible const libraryID = tp.frontmatter.libraryID || 1; // Run the import app.plugins.getPlugin('obsidian-zotero-desktop-connector').runImport('IMPORT NAME', citekey, libraryID); ; %>

{# version: 3.6 -#}

citekey: {{citekey}} aliases:

  • "{%- if creators -%} {{creators[0].lastName or creators[0].name }} {%- if creators|length == 2 %} & {{creators[1].lastName or creators[1].name}}{% endif -%} {%- if creators|length > 2 %} et al.{% endif -%} {%- endif -%} {%- if date %} ({{date | format("YYYY")}}){% endif -%} {%- if shortTitle %} {{shortTitle | safe}} {%- else %} {{title | safe}} {%- endif -%}"{% if itemType == "bookSection" %} book-title: "{{bookTitle | replace('"',"'")}}"{% endif %} title: "{{title | replace('"',"'")}}" {%- set camelRegex = r/([a-z])([A-Z])/g %} {%- for type, creators in creators | groupby("creatorType") %} {% if creators.length > 1 %}{{type | replace(camelRegex, "$1 $2") | lower | trim}}s:{%- for creator in creators %}{% if creator.name %}
  • {{creator.name}}{% else%}
  • {{creator.firstName}} {{creator.lastName}} {% endif %}{%- endfor %} {% else -%} {{type | replace(camelRegex, "$1-$2") | lower | trim}}:{%- for creator in creators %}{% if creator.name %} "{{creator.name}}"{% else%} "{{creator.firstName}} {{creator.lastName}}"{% endif -%}{%- endfor -%}{% endif -%}{% endfor %} year: {% if date %}{{date | format("YYYY")}}{% endif %} item-type: {{itemType | replace(camelRegex, "$1 $2") | title | trim}} publisher: {% if publicationTitle %}"{{publicationTitle}}"{% else %}"{{publisher}}"{% endif %} {%- if notes.length > 0 -%} {%- set longShortCutoff = 20 -%} {%- set shortnotes = [] -%} {%- set longnotes = [] -%} {%- for note in notes -%} {%- if note.note | wordcount <= longShortCutoff -%} {%- set shortnotes = (shortnotes.push(note.note), shortnotes) -%} {%- else -%} {%- set longnotes = (longnotes.push(note), longnotes) -%} {%- endif -%}{%- endfor -%}{%- endif -%} {%- for comment in shortnotes %} {%- if comment and loop.first %} comments: {% endif -%}
  • "{{comment|replace('"',"'")| replace("\n"," ")}}"{% endfor %} tags:{% for t in tags %}
  • {{t.tag | replace(r/\s+/g, "-")}}{% endfor %}{% if DOI %} doi: https://doi.org/{{DOI}}{% endif %}{% if itemType == "book" %} ISBN: {{ISBN}}{% endif %} cssclasses:
  • literature-note{% if attachments.length > 0 %}{% for attachment in attachments %}{% if loop.first %} attachments:{% endif %}
  • {{attachment.path}}{% endfor %}{% endif %} libraryID: {{libraryID}}

BUTTON[update-litnote]

{% persist "notes" -%} {%- if isFirstImport %}

{# ==The following sections (Key takeaways and Processing) are not filled automatically. They are for for you to write into manually.== -#}

Key takeaways

{#- The following is a cursor placeholder for the Templater plugin. After importing the note, you can jump to each of these with an assigned hotkey like ctrl+J #}

  • <% tp.file.cursor(1) %>

Processing

  • Status:: new
  • Connections:: <% tp.file.cursor(4) %>
  • Projects::

{% endif %}{% endpersist %}

[!info]- Info 🔗 Zotero{% if DOI %} | DOI{% endif %}{% for attachment in attachments | filterby("path", "endswith", ".pdf") %} | [PDF-{{loop.index}}](file:///{{attachment.path | replace(" ", "%20")}}){%- endfor %}

{% if bibliography %}Bibliography: {{bibliography|replace("\n","" )}}{% endif %}

Authors:: {% for a in creators %} [[03 - Source notes/People/{{a.firstName}} {{a.lastName}}|{{a.firstName}} {{a.lastName}}]]{% if not loop.last %}, {% endif %}{% endfor %}

{% if tags %}Tags: {% for t in tags %}#{{t.tag | replace(r/\s+/g, "-")}}{% if not loop.last %}, {% endif %}{% endfor %}{% endif %}

Collections:: {% for collection in collections %}[[{{collection.name}}]]{% if not loop.last %}, {% endif %}{% endfor -%} {%- set readingSpeed = 220 %} {%- set wordsPerPage = 360 %} {%- if pages %} {%- set pageRegex = r/(\d+)-(\d+)/ %} {%- set splitPages = pageRegex.test(pages) %} {%- if splitPages %} {%- set pageMatch = pageRegex.exec(pages) %} {%- set firstPage = pageMatch[1] %} {%- set pageCount = pageMatch[2] - pageMatch[1] %} {%- else %} {%- set pageCount = pages %} {%- endif %} {%- elif numPages %} {%- set pageCount = numPages %} {%- else %} {%- set pageCount = 0 %} {% endif -%} {%- if firstPage %}

First-page:: {{firstPage}} {%- endif -%} {%- if pageCount > 0 -%} {%- set readingTime = ((pageCount* wordsPerPage)/readingSpeed)/60 %}

Page-count:: {{pageCount}}

Reading-time:: {% if readingTime < 1 %}{{(readingTime * 60) | round + " minutes"}}{% else %}{{readingTime | round(3) + " hours"}}{% endif %}{% endif %}

[!abstract]- {% if abstractNote %} {{abstractNote|replace("\n","\n>")|striptags(true)|replace("Objectives", "Objectives")|replace("Background", "Background")|replace("Methodology", "Methodology")|replace("Results","Results")|replace("Conclusion","Conclusion")}} {% endif %}

[!quote]- Citations

content: "@{{citekey}}" -file:@{{citekey}}

{%- set headingRegex = r/^#+/ -%} {%- set titleRegex = r/^#+./ -%} {%- set lineRegex = r/^.$/m %} {%- if longnotes.length > 0 -%} {%- for n in longnotes -%} {%- if n and loop.first %}

[!note]- Zotero notes ({{longnotes.length}})

Notes longer than {{longShortCutoff}} words. {%- endif %}

[!example]- Note {{loop.index}} |{%- if headingRegex.test(n.note) == true %}{{n.note | replace(n.note,titleRegex.exec(n.note))|replace(headingRegex,"")}}{% else %} {{lineRegex.exec(n.note | truncate(30))}} {% endif %} {{n.note | replace("\n", "\n>> ")| replace(titleRegex, "")}}{% if n.tags.length > 0 %}

Tags:{% for t in n.tags %} #{{t.tag}}{% if not loop.last %}, {% endif %}{% endfor %}{% endif -%}{%- if not loop.last %} {%- endif -%} {%- endfor -%}{%- endif %}


Reading notes

{% set colorValueMap = { "#2ea8e5": { "colorCategory": "Blue", "heading": "❓ Problem formulation", "symbol": "?" }, "#5fb236": { "colorCategory": "Green", "heading": "🎯 Key takeaways", "symbol": "$" }, "#ffd400": { "colorCategory": "Yellow", "heading": "💬 Evidence and arguments", "symbol": "&" }, "#f19837": { "colorCategory": "Orange", "heading": "✅ Actionable takeaways", "symbol": "!" }, "#a28ae5": { "colorCategory": "Purple", "heading": "🧩 Concepts and frameworks", "symbol": "~" }, "#e56eee": { "colorCategory": "Magenta", "heading": "🗺️ Context and connections", "symbol": "€" }, "#ff6666": { "colorCategory": "Red", "heading": "🚧 Digging and disclaimers", "symbol": "£" }, "#aaaaaa": { "colorCategory": "Gray", "heading": "📌 Statistics and info", "symbol": "%" } } -%}

{%- macro tagFormatter(annotation) -%} {% if annotation.tags -%} {%- for t in annotation.tags %} #{{ t.tag | replace(r/\s+/g, "-") }}{% if not loop.last %}, {% endif %}{%- endfor %} {%- endif %} {%- endmacro -%}

{% persist "annotations" %} {% set annotations = annotations | filterby("date", "dateafter", lastImportDate) -%} {% if annotations.length > 0 %} Imported on [[{{importDate | format("YYYY-MM-DD")}}]] at {{importDate | format("HH:mm")}}

{%- set grouped_annotations = annotations | groupby("color") -%} {%- for color, colorValue in colorValueMap -%} {%- if color in grouped_annotations -%} {%- set annotations = grouped_annotations[color] -%} {%- for annotation in annotations -%} {%- set citationLink = '[(p. ' ~ annotation.pageLabel ~ ')](' ~ annotation.desktopURI ~ ')' %} {%- set tagString = tagFormatter(annotation) %}

{%- if annotation and loop.first %}

{{colorValue.heading}} %% fold %%

{% endif -%}

{%- if annotation.imageRelativePath %}

[!cite]+ Image {{citationLink}} ![[{{annotation.imageRelativePath}}]]{% if annotation.tags %} {{tagString}}{% endif %}{%- if (annotation.comment or []).indexOf("todo ") !== -1 %}

  • {{annotation.comment | replace("todo ", "")}}{%- elif annotation.comment %} {{annotation.comment}}{%- endif %} {% elif (annotation.comment or []).indexOf("todo ") !== -1 %}
  • {{annotation.comment | replace("todo ", "")}}:{% if not annotation.annotatedText %} {{citationLink}}{% else %}
    • {{colorValue.symbol}} {{annotation.annotatedText | replace(r/\s+/g, " ")}} {{citationLink}}{{tagString}}{% endif -%} {% elif annotation.comment %}
  • {{annotation.comment}}:{% if not annotation.annotatedText %} {{citationLink}}{% else %}
    • {{colorValue.symbol}} {{annotation.annotatedText | replace(r/\s+/g, " ") }} {{citationLink}}{{tagString}}{% endif -%} {%- elif annotation.annotatedText %}
  • {{colorValue.symbol}} {{annotation.annotatedText | replace(r/\s+/g, " ") }} {{citationLink}}{{tagString}} {%- endif -%}{%- endfor %}{%- endif -%} {% endfor -%} {% endif %}

{% endpersist %}

@thesaltydispatcher
Copy link

@FeralFlora Ahhh my mistake, that's exactly how I was trying to apply it. I guess I need to spend some more time in figuring out the initial importing. I appreciate your response!

@FeralFlora
Copy link
Author

@thesaltydispatcher No worries. This video should help you get started with the Zotero Integration plugin: https://youtu.be/CGGeMrtyjBI

@GH4TP
Copy link

GH4TP commented Jan 16, 2025

What's the rationale for the section that starts "[!note]- Zotero notes ({{longnotes.length}})" please @FeralFlora ? Are there particular considerations relating to note length related to Obsidian, Zotero, or the Obsidian Zotero plugin? Thanks :-)

@FeralFlora
Copy link
Author

FeralFlora commented Jan 16, 2025

@GH4TP Well, first of all, in this particular excerpt, longnotes.length just means the length of the longnotes array - in otherwords the number of long notes, which is written in parentheses in the Zotero notes callout. But what is a long note? Well, by default, it's just a note in Zotero (attached to an item) which is longer than 20 words, as configured with {%- set longShortCutoff = 20 -%} earlier in the template. You can change this cutoff value to whatever you like.

Short notes are added to the YAML properties of the literature note under the "comments" property, while longer notes are stored as nested callouts in the section you copied that excerpt from. The rationale is for notes like "This is very useful for my project" to be stored as comments, while longer notes with multiple paragraphs are stored as nested callouts further down in the literature note:

image

If you want to change this behavior, so that all notes are added to the "Zotero notes" as nested callouts, you can set the longShortCutoff to 0.

@Shade1698
Copy link

Shade1698 commented Jan 18, 2025

Hello, first of all, thank you so much for this template! I really like it a lot. I'm only using the 'Reading Notes' section as I have a different set up for the metadata.

I am running into 2 main issues:

  1. Blank lines (they are not spaces from the CSS styling) and some metadata(?) that is generated at the beginning and end of the reading notes.
  2. Blank line generated after each tag heading.
    image

Here is the code that produces this output. I have adapted the tags:

    "#ffd400": {
        "colorCategory": "Yellow",
        "heading": "📖 Theory",
        "symbol": "&"
    },
    "#ff6666": {
        "colorCategory": "Red",
        "heading": "🚧 Challenges",
        "symbol": "!"
    },
    "#5fb236": {
        "colorCategory": "Green",
        "heading": "🧪 Wet Lab",
        "symbol": "$"
    },
    "#2ea8e5": {
        "colorCategory": "Blue",
        "heading": "📊 Statistics",
        "symbol": "^^"
    },
    "#a28ae5": {
        "colorCategory": "Purple",
        "heading": "💻 Bioinformatics",
        "symbol": "~"
    },
    "#e56eee": {
        "colorCategory": "Magenta",
        "heading": "✅ Results",
        "symbol": "€"
    },
	"#f19837": {
        "colorCategory": "Orange",
        "heading": "🔗 Citation Chaining",
        "symbol": "@"
    },
    "#aaaaaa": {
        "colorCategory": "Gray",
        "heading": "❓ Questions",
        "symbol": "?"
    }
} -%}

{%- macro tagFormatter(annotation) -%}
    {% if annotation.tags -%}
        {%- for t in annotation.tags %} #{{ t.tag | replace(r/\s+/g, "-") }}{% if not loop.last %}, {% endif %}{%- endfor %}
    {%- endif %}
{%- endmacro -%}

{% persist "annotations" %}
{% set annotations = annotations | filterby("date", "dateafter", lastImportDate) -%}
{% if annotations.length > 0 %}

{%- set grouped_annotations = annotations | groupby("color") -%}
{%- for color, colorValue in colorValueMap -%}
{%- if color in grouped_annotations -%} 
{%- set annotations = grouped_annotations[color] -%}
{%- for annotation in annotations -%}
{%- set citationLink = '[(p. ' ~ annotation.pageLabel ~ ')](' ~ annotation.desktopURI ~ ')' %}
{%- set tagString = tagFormatter(annotation) %}

{%- if annotation and loop.first %}

### {{colorValue.heading}} 
{% endif -%}

{%- if annotation.imageRelativePath %}

> [!cite]+ Image {{citationLink}}
> ![[{{annotation.imageRelativePath}}]]{% if annotation.tags %}
> {{tagString}}{% endif %}{%- if (annotation.comment or []).indexOf("todo ") !== -1 %}
> - [ ] {{annotation.comment | replace("todo ", "")}}{%- elif annotation.comment %}
> {{annotation.comment}}**{%- endif %}
{% elif (annotation.comment or []).indexOf("todo ") !== -1 %}
- [ ] {{annotation.comment | replace("todo ", "")}}:{% if not annotation.annotatedText %} {{citationLink}}{% else %}
	- {{colorValue.symbol}}  {{annotation.annotatedText | replace(r/\s+/g, " ")}} {{citationLink}}{{tagString}}{% endif -%}
{% elif annotation.comment %}
- {{annotation.comment}}:{% if not annotation.annotatedText %} {{citationLink}}{% else %}
	- {{colorValue.symbol}}  {{annotation.annotatedText | replace(r/\s+/g, " ") }} {{citationLink}}{{tagString}}{% endif -%}
{%- elif annotation.annotatedText %}
- {{colorValue.symbol}}  {{annotation.annotatedText | replace(r/\s+/g, " ") }} {{citationLink}}{{tagString}}
{%- endif -%}{%- endfor %}{%- endif -%}
{% endfor -%}
{% endif %}

{% endpersist %}

Thank you for taking a look!

@GH4TP
Copy link

GH4TP commented Jan 19, 2025

Short notes are added to the YAML properties of the literature note under the "comments" property, while longer notes are stored as nested callouts in the section you copied that excerpt from. The rationale is for notes like "This is very useful for my project" to be stored as comments, while longer notes with multiple paragraphs are stored as nested callouts further down in the literature note:

Thanks for taking the time to reply, @FeralFlora . It is the positioning of the long notes above reading notes in relation to the academic workflow that you had in mind when you designed your template that I was curious about.

@FeralFlora
Copy link
Author

It is the positioning of the long notes above reading notes in relation to the academic workflow that you had in mind when you designed your template that I was curious about.

Thanks for the clarification. I made the "Zotero notes" callout for notes in Zotero, e.g. note files attached to an item. See:
https://www.zotero.org/support/notes

On the other hand, "reading notes" refers to highlights and annotations made during reading. These are not separate files attached to the item as a whole, but annotations made in the PDF, EPUB or snapshot.

I don't make much use of notes in Zotero, since I mostly make my notes in Obsidian, but I do my annotations in Zotero. So I guess the "Zotero notes" section is just there in case I've made some note. My main focus is the annotations or "reading notes". Feel free to change the order or the naming of these sections to suit your own workflow.

@GH4TP
Copy link

GH4TP commented Jan 22, 2025

I don't make much use of notes in Zotero, since I mostly make my notes in Obsidian, but I do my annotations in Zotero.

I'm the same. I primarily use annotation notes and annotation comments. In fact, I hadn't noticed the long notes callout until I added a bunch of author's notes to a paper I was reading. When I was writing up my summary in Obsidian I discovered these because I had to scroll through them to get to the annotations. Which prompted my question about positioning these; I'd put them after the annoations, personally.

Hey, I also want to thank you for all the effort you put in to help with these templates and for sharing your experiences and knowledge. It really is appreciated very much.

@FeralFlora
Copy link
Author

I had to scroll through them to get to the annotations.

The callout is collapsed by default, so you shouldn't have to scroll through them (unless you're using source mode primarily?). But of course, you're free to move that part of the template to the end.

Hey, I also want to thank you for all the effort you put in to help with these templates and for sharing your experiences and knowledge. It really is appreciated very much.

Thanks for saying that, I appreciate it :)

@GH4TP
Copy link

GH4TP commented Jan 22, 2025

The callout is collapsed by default, so you shouldn't have to scroll through them
Sorry I wasn't clear, @FeralFlora . I should have said scrolling when I'm linking from a different Obsidian note to a block text within the lit note i.e. using the syntax [[ blahblah#^]]

@IndexLibrorumProhibitorum
Copy link

IndexLibrorumProhibitorum commented Jan 28, 2025

Hello, first of all, thank you so much for this template! I really like it a lot. I'm only using the 'Reading Notes' section as I have a different set up for the metadata.

I am running into 2 main issues:

  1. Blank lines (they are not spaces from the CSS styling) and some metadata(?) that is generated at the beginning and end of the reading notes.
  2. Blank line generated after each tag heading.
    ...

I'm looking for the same modifications. @FeralFlora could you advise?

@Shade1698
Copy link

@IndexLibrorumProhibitorum hey, not sure if this will be useful to you but I was able to get rid of it. I am not sure if it affects the refresh capabilities since I rarely go and add new annotations to the Zotero PDF file once I'm done. I am a code newbie so this is just what worked for me. @FeralFlora will have the correct answer, but in case you urgently need an answer, here is what worked for me with the changes listed below:

  1. No %% annotations at the beginning or end (removed {% persist "annotations" %} block).
  2. No blank lines before the ## Notes heading.
  3. There is now a blank line and divider separating each of the subsections (divider lines (---) are conditionally inserted between sections based on whether the section has content (annotations). This is controlled with the firstSectionRendered flag).

Code

{% set colorValueMap = {
"#ffd400": {
"colorCategory": "Yellow",
"heading": "📖 Theory",
"symbol": "&"
},
"#ff6666": {
"colorCategory": "Red",
"heading": "🚧 Challenges",
"symbol": "!"
},
"#5fb236": {
"colorCategory": "Green",
"heading": "🧪 Wet Lab",
"symbol": "$"
},
"#2ea8e5": {
"colorCategory": "Blue",
"heading": "📊 Statistics",
"symbol": "^^"
},
"#a28ae5": {
"colorCategory": "Purple",
"heading": "💻 Bioinformatics",
"symbol": "~"
},
"#e56eee": {
"colorCategory": "Magenta",
"heading": "✅ Results",
"symbol": "€"
},
"#f19837": {
"colorCategory": "Orange",
"heading": "🔗 Citation Chaining",
"symbol": "@"
},
"#aaaaaa": {
"colorCategory": "Gray",
"heading": "❓ Questions",
"symbol": "?"
}
} -%}

{%- macro tagFormatter(annotation) -%}
{% if annotation.tags -%}
{%- for t in annotation.tags %} #{{ t.tag | replace(r/\s+/g, "-") }}{% if not loop.last %}, {% endif %}{%- endfor %}
{%- endif %}
{%- endmacro -%}

## Notes
{%- set annotations = annotations | filterby("date", "dateafter", lastImportDate) -%}
{% if annotations.length > 0 %}
{%- set grouped_annotations = annotations | groupby("color") -%}
{%- set firstSectionRendered = false -%}
{%- for color, colorValue in colorValueMap -%}
{%- if color in grouped_annotations -%}
{%- set annotations = grouped_annotations[color] -%}
{%- if annotations.length > 0 %}
{%- if firstSectionRendered %}
---
{%- endif %}
{%- set firstSectionRendered = true %}
{%- for annotation in annotations -%}
{%- set citationLink = '[(p. ' ~ annotation.pageLabel ~ ')](' ~ annotation.desktopURI ~ ')' %}
{%- set tagString = tagFormatter(annotation) %}
{%- if annotation and loop.first %}
### {{ colorValue.heading }}
{%- endif -%}
{%- if annotation.imageRelativePath %}
> [!cite]+ Image {{citationLink}}
> ![[{{annotation.imageRelativePath}}]]{% if annotation.tags %}
> {{tagString}}{% endif %}{%- if (annotation.comment or []).indexOf("todo ") !== -1 %}
> - [ ] {{annotation.comment | replace("todo ", "")}}{%- elif annotation.comment %}
> {{annotation.comment}}**{%- endif %}
{% elif (annotation.comment or []).indexOf("todo ") !== -1 %}
- [ ] {{annotation.comment | replace("todo ", "")}}:{% if not annotation.annotatedText %} {{citationLink}}{% else %}
	- {{colorValue.symbol}}  {{annotation.annotatedText | replace(r/\s+/g, " ")}} {{citationLink}}{{tagString}}{% endif -%}
{% elif annotation.comment %}
- {{annotation.comment}}:{% if not annotation.annotatedText %} {{citationLink}}{% else %}
	- {{colorValue.symbol}}  {{annotation.annotatedText | replace(r/\s+/g, " ") }} {{citationLink}}{{tagString}}{% endif -%}
{%- elif annotation.annotatedText %}
- {{colorValue.symbol}}  {{annotation.annotatedText | replace(r/\s+/g, " ") }} {{citationLink}}{{tagString}}
{%- endif -%}
{%- endfor %}
{%- endif %}
{%- endif %}
{%- endfor -%}
{% endif %}

A screenshot of the beginning and end of the output:
image
image

@FeralFlora
Copy link
Author

I am running into 2 main issues:

1. Blank lines (they are not spaces from the CSS styling) and some metadata(?) that is generated at the beginning and end of the reading notes.

2. Blank line generated after each tag heading.

Hi @Shade1698 and @IndexLibrorumProhibitorum,

I see you want to remove the blank lines before and after headings, but I would advice you to "let your markdown breathe". However, if you want to go ahead with this, it should be simple. @Shade1698's changes seem to have done the job via some whitespace control (useful to know).

I am not sure if it affects the refresh capabilities since I rarely go and add new annotations to the Zotero PDF file once I'm done

It does!

I would also strongly advice against removing the section you call "some metadata", which is what's called a "persistent field". This means that everything imported into such a field is safe against being overwritten if you ever update your literature note - it persists across updates. This persistent field is a prerequisite for being able to safely add comments to your imported highlights in Obsidian. Without the persistent field, all your changes on the Obsidian side will be lost if you ever update a literature note. This includes things like block-ids if you're linking to specific annotations or embedding them in other notes.

@FeralFlora
Copy link
Author

@Shade1698 The last section you marked ("Import date") is not part of the template. It's added automatically by Zotero Integration.

@IndexLibrorumProhibitorum
Copy link

IndexLibrorumProhibitorum commented Jan 29, 2025

@Shade1698 Thank you for your comment. As @FeralFlora has already mentioned, removing the persistent tags from the code will have significant consequences when refreshing the import. Any solution to this 'problem' (such as it is) should keep the tags in the code in the template, but hide the little tags in the document. I have grown convinced that this is simply something I have to live with, however.

@FeralFlora Thank you for your help, and I wanted to thank you explicitly for the amount of time you've put into this project. That you're still responding to questions after your first post in March 2023 (!) is wonderful. I'll give the "let your markdown breathe" post a read, though I have managed to remove the extra white space on my own already. Might revert back ;)

I'm currently struggling with having new notes and annotations show up under already existent headers, as someone else has indicated is an issue here. You mentioned that you were working on a workaround for this. Have you had any luck with this?

@DaveSamuels1998
Copy link

Hello, I was wonder if the template from the "runImport.md" was working here?
Screenshot 2025-02-04 at 1 08 45 PM

@FeralFlora
Copy link
Author

@DaveSamuels1998 The runImport template only comes into play when you need to update your literature note with new Zotero changes. So there's no way for me to tell if it's working based on that screenshot.

But I can tell that you haven't enabled the List callouts plugin, because then the highlights would be colored as in Zotero. My literature note template is made to work with the List callouts plugin.

@FeralFlora
Copy link
Author

@IndexLibrorumProhibitorum thanks for the appreciation. I enjoy sharing my work and helping others :)

And, as you mention, I'm not quite done yet as there still improvements left to do. I have some ideas on how to have persistence and still be able to group annotations without duplication of headings. One way would involved more persistent fields, one for each color. The other would involve doing the persistence ourselves using javascript in Templater. However, the complexity of this is quite high. So I'm still mulling it over.

@IndexLibrorumProhibitorum

@FeralFlora Gotcha, thanks for giving it some thought though.

To share a tiny tiny micro-contribution of my own: When reviewing papers, I create new notes for concepts that I expect will tie several papers together. An example would be 'Organ transplantation', which naturally takes quotes and info from different papers. Using the Zotero integration plugin it's quite easy to just cite the paper as one normally does, but I noticed that such a citation wouldn't be registered under the "citations" block on the paper's own page. This is because the citation just gets formatted without explicitly using the citekey, which is what that citations block searches for.

Using the citation output format of 'Template', however, lets you set your own format that does allow you to use the citekey, and create a clickable link to that page. The following has worked well for me so far:

([[{{citekey}}|{{ creators[0].lastName }} {% if date %}{{ date | format("YYYY") }}{% endif %}]])

image

image

image

@DaveSamuels1998
Copy link

@DaveSamuels1998 The runImport template only comes into play when you need to update your literature note with new Zotero changes. So there's no way for me to tell if it's working based on that screenshot.

But I can tell that you haven't enabled the List callouts plugin, because then the highlights would be colored as in Zotero. My literature note template is made to work with the List callouts plugin.

Hello, for the Meta Bind Button Templates, what would be the beginning of the path? Is it the name of my Vault or the folder that the runImport.md is in?
For example, the name of my Vault is Personal Notes. Would I put command: templater-obsidian:07 - Personal Notes/Templates/runImport.md or would I put command: templater-obsidian:07 - Templates/runImport.md?
I tried both and I couldn't get my button to show updates to my document.

@FeralFlora
Copy link
Author

@DaveSamuels1998 What you are specifying in the button template is actually a Templater command that happens to specify the path of the template it executes as part of its command name. So you can just look in the command palette to see how the path should be specified.

In my case, 07 - is actually part of the path. My top level folders are numbered to order them, so it's 07 - Bins. I doubt your templates reside in a folder with the exact same numbering as I use, so you need to remove that part.

As for your two examples, if "Personal notes" is the vault, you should start with "Templates". You just need the part of the path that's inside the vault. But again, just look in the command palette and you'll see the correct path / command name.

@Shade1698
Copy link

@FeralFlora thank you so much for explaining what those sections are and why it's so important to keep them. I appreciate it! Not much else to say, but I really wanted to thank you for sharing the code and being so responsive to all the questions. You've made a big difference in how I easily I'm able to do my research, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment