Zotero Integration – Import Templates?

ohhh that works. thanks!

Nice! Now that I see it, the reversion of importance, if I can call it that, makes total sense: in the source, your comment is secondary in the sense that it is a comment triggered by something in the text. But when you bring it into Obsidian (which is primarily about your own thinking) that comment becomes the primary thing and the text that triggered it is added for context.

And the bullet list format is much easier to handle than the callout format I’ve been using so far. Including the ingenious idea with the todo items!

The only thing I’ll have to think about before adopting this template are the colours. Currently, I have the callouts in the same colour as the original highlights, which helps for recognition. Unfortunately, Obsidian doesn’t support multiple highlighting colours, but I found the highlightr plugin which adds exactly that.

Not sure I want to add another plugin, though,… Another disadvantage of highlighting all the highlights in obsidian (regardless of colour) is that I can’t highlight parts of the highlight later in. This is something I do quite often when going through my annotations, to make it easier to quickly grasp the core point of the highlight.

Okay, think I’ll stop my thinking-out-loud here. Just wanted to highlight the ingenuity of this solution.

If anybody has adapted the zettelizer macro to turn each bullet point into a separate note (see here), please post it here!

Or perhaps it is easier to adjust the Zotero integration template so that it adds a heading before each annotation (which the is what the Zettelizer macro uses to extract notes)?

In fact, yes, I think that’s actually the way to go, because that way I can make sure that only annotations in a certain colour will be turned into notes, or, even better: only the ones that have comments. yay!

Wow, I just wanted to write a quick response and figure things out later, but it looks like writing that quick response made me figure stuff out. Writing is thinking.

1 Like

Thanks for sharing the highlighting. One question: how do I get black text in the highlighted portion? My text is showing up white which is tough to read.

Hi all, I am struggling with my zotero integration template.

{% for author in authors %} [[{{author}}]] {% endfor %}

creates a link for every single letter of each author. :confused:

What am I missing? Can anybody help?
Thanks in advance!

Try this if you want to bring each author separately [{% for a in creators %}{{a.firstName}} {{a.lastName}}{% if not loop.last %}, {% endif %} {% endfor %}]

2 Likes

@PR-C Thanks for your suggestion - I can probably only try it out on Monday. Will give a feedback if that solves my problem! :slightly_smiling_face:

That did not work, but a slight modification of your code did the trick:

{% for a in creators %} [[{{a.firstName}} {{a.lastName}}]]{% if not loop.last %}, {% endif %}{% endfor %}

Thanks a lot!

1 Like

Thank you both for your help, it is much appreciated. I hope you have a nice day/week :slight_smile:

Hey everyone!
I just wanted to let you know that I’ve completely updated my template, merged annotations and notes back together into one big literature note, and have moved it into a template repository. You can find the new version here: obsidian-templates/zotero.md at main · lguenth/obsidian-templates · GitHub

I’m really happy with this approach. Index at the top, then a brief metadata box and the annotations at the bottom, grouped by headings so you can collapse them. Also using callouts now instead of bullet points because I find it easier to select & copy quotes from them.

Features:

  1. Handles both the Zotero colors from the built-in PDF viewser as well as the color categories added by the ZI plugin. This fixes the issue with Zotero’s purple color being grouped as “Blue”, for examples.
  2. Annotations are grouped by colors, with custom headings for each. And: You can choose a custom sort order for them, so if you want main ideas first and caveats/tasks at the bottom, you can do that now. They’re not ordered by their appearance in the paper anymore.
  3. Identifies two annotation categories (highlight or image). If you want strikethroughs/underlines etc take a look at mgmeyers template, for example.
  4. All the usual stuff like persisting old annotations and only addings new highlights on re-import.
  5. Doesn’t overwrite the note/index and metadata section at the top at re-import!

Here’s what that looks like:

5 Likes

Really like this template, thanks for putting in the effort! A question and a comment:

  1. Question first: Just to make sure, from looking at the template it looks like the Index section you mention is for me to write directly in the note - or is it supposed to get that from anywhere?
  2. If I re-import the same paper twice, the metadata section disappears on the second import. Removing the {% if isFirstImport %} (and {% endif %}) in the beginning of the note solves it. Did you have that in there for some reason, or is it just a small bug?
1 Like

Hey! I’m glad you like it!
The index part as well as the metadata part are space for my own notes and comments. The index is my approach to Zettelkasten-style literature notes, where I note down claims/ideas/concepts from specific pages.
The isFirstImport should make it so that my handwritten notes never get overwritten… at least that was the plan. But you’re right, there seems to be a bug. I’ll update the template and comment here once I’ve solved it.

Hi lovely people! Thank you all for your sharing. I’ve been obsessed with the Zotero-Obsidian workflow lately and found this very intriguing. Inspired by the beautiful template by @apfelstrudelig and the recent youtube video by @tallguyjenks, I made my template of the ultimate version.

Most importantly, the problem with note overwriting from re-import is fixed (which I believe has also been reported by @roaldarbol )

This is what it looks like

Metadata with dataview of related items:

Notes section and Annotation section:

More callouts and images

This is my template:

---
aliases: {{citekey}}
publisher: "{{publicationTitle}}"
url: {{url}}
doi: {{DOI}}
tags: [literature-note, zotero, {{publicationTitle | replace(" ", "-")}}, {% for t in tags %}{{t.tag}}{% if not loop.last %}, {% endif %}{% endfor %}]
---

# {{title}}

> [!abstract]- 
> {% if abstractNote %} 
> {{abstractNote|replace("\n"," ")}}
> {% endif %}

---
---
## Index:
### Metadata
> [!meta]- Metadata – {% for attachment in attachments | filterby("path", "endswith", ".pdf") %}[PDF{% if not loop.first %} {{loop.index}}{% endif %}]({{attachment.desktopURI|replace("/select/", "/open-pdf/")}}){% if not loop.last %}, {% endif %}{% endfor %}
> **Title**:: {{title}}  
> **Authors**:: {%- for creator in creators %} {%- if creator.name == null %} {{creator.firstName}} {{creator.lastName}}, {%- endif -%} {%- if creator.name %}**{{creator.creatorType | capitalize}}**:: {{creator.name}}{%- endif -%}{%- endfor %}
> **Year**:: {{date | format("YYYY")}} 
> {%- if itemType %}**ItemType**:: {{itemType}}{%- endif %}  
> {%- if itemType == "journalArticle" %}**Journal**:: *{{publicationTitle}}* {%- endif %} {%- if itemType == "bookSection" %}**Book**:: {{publicationTitle}} {%- endif %}
> {% if hashTags %}**Keywords**:: {{hashTags}}{% endif %}
> **Related**:: {% for relation in relations -%} {%- if relation.citekey -%} [[{{relation.citekey}}]], {% endif -%} {%- endfor%}

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

## Main ideas:
- 
## Methodology:
- 
## Results:
- 
## Key points:
- 
{% endif %}{% endpersist %}
## Reading notes
{% persist "annotations" %}
{%-
    set zoteroColors = {
        "#ff6666": "red",
        "#f19837": "orange",
        "#5fb236": "green",
        "#ffd400": "yellow",
        "#2ea8e5": "blue",
        "#a28ae5": "purple",
        "#e56eee": "magenta",
        "#aaaaaa": "grey"
    }
-%}

{%-
   set colorHeading = {
		"red": "⭕ Very important or questionable",
		"orange": "⭐ Important or interesting",
		"green": "✅ Major statements",
		"yellow": "📚 Ordinary notes",
        "blue": "🔗 Interesting references",
        "purple": "🧩 Methodology",
        "other": "Misc"
   }
-%}

{%- macro calloutHeader(type) -%}
    {%- switch type -%}
        {%- case "highlight" -%}
        Highlight
        {%- case "image" -%}
        Image
        {%- default -%}
        Note
    {%- endswitch -%}
{%- endmacro %}

{%- set newAnnot = [] -%}
{%- set newAnnotations = [] -%}
{%- set annotations = annotations | filterby("date", "dateafter", lastImportDate) %}

{% if annotations.length > 0 %}
*Imported: {{importDate | format("YYYY-MM-DD HH:mm")}}*

{%- for annot in annotations -%}

    {%- if annot.color in zoteroColors -%}
        {%- set customColor = zoteroColors[annot.color] -%}
    {%- elif annot.colorCategory|lower in colorHeading -%}
    	{%- set customColor = annot.colorCategory|lower -%}
    {%- else -%}
	    {%- set customColor = "other" -%}
    {%- endif -%}

    {%- set newAnnotations = (newAnnotations.push({"annotation": annot, "customColor": customColor}), newAnnotations) -%}

{%- endfor -%}

{#- INSERT ANNOTATIONS -#}
{#- Loops through each of the available colors and only inserts matching annotations -#}
{#- This is a workaround for inserting categories in a predefined order (instead of using groupby & the order in which they appear in the PDF) -#}

{%- for color, heading in colorHeading -%}
{%- for entry in newAnnotations | filterby ("customColor", "startswith", color) -%}
{%- set annot = entry.annotation -%}

{%- if entry and loop.first %}

### {{colorHeading[color]}}
{%- endif %}

> [!quote{{"|" + color if color != "other"}}]+ {{calloutHeader(annot.type)}} ([page. {{annot.pageLabel}}](zotero://open-pdf/library/items/{{annot.attachment.itemKey}}?page={{annot.pageLabel}}&annotation={{annot.id}}))

{%- if annot.annotatedText %}
> {{annot.annotatedText|nl2br}} {% if annot.hashTags %}{{annot.hashTags}}{% endif -%}
{%- endif %}

{%- if annot.imageRelativePath %}
> ![[{{annot.imageRelativePath}}]]
{%- endif %}

{%- if annot.ocrText %}
> {{annot.ocrText}}
{%- endif %}

{%- if annot.comment %}
> - **{{annot.comment|nl2br}}**
{%- endif -%}

{%- endfor -%}
{%- endfor -%}
{% endif %}
{% endpersist -%}

A few remarks:

  1. Some of the colors are customed by the theme, you can be creative with these
  2. I prefer hashtags to links at the moment, so most of the tags are in the hashtag format, but if you prefer links that come with more degrees of freedom, you are welcome to change those
  3. The handwritten notes part (main ideas, methodology…) is bounded by
{% persist "notes" %}{% if isFirstImport %}
{% endif %}{% endpersist %}

so that the template only creates these tiles when the file is imported the first time. Thus you can edit this section later on without worrying about overwriting.
4. The annotation section is mostly inspired by the template from @apfelstrudelig , so I’ll just spare the details (no clue about the details haha)

7 Likes

NOTE: Somehow the code block for the dataview is messing with the code block in my answer above, so here I just put up a screenshot (which is rather simple):

you just need to put it under the Metadate part and that’s it (or you can move it somewhere you like or just forget about it)

Cheers!

PS. The theme is AnuPpuccin with a few style settings

2 Likes

Thanks for sharing this, really useful :slight_smile: One thing that happens to me is that if I use your template, I get all the headers and the heading symbols as in your picture, but everything is in a grey colour, meaning that Major Statements are in grey and Ordinary notes are in grey too, as opposed to having green and yellow callout boxes. Any idea on why this is the case, as I am not changing your template?

Hey @tophee, sorry for not responding earlier. I appreciate your thoughts and feedback.

You and others may appreciate an update of the list-based template, now that I returned to Zotero Integration until Obsidian-Zotero is more stable.

I’ve addressed your comment on the highlights / colors, and made a host of other improvements (see below). I also found it a bit limiting to have all the ==highlights== in the same color, and the readability wasn’t great. Plus, like you mention, it meant forgoing the ability to highlight within the highlight, which I hadn’t considered.

Main template features

  1. As before, annotations and comments are formatted as a bullet list, where comments are listed in bold before the highlight they belong to, which is indented below and highlighted, now using List callouts.
  2. If a highlight or post-it comment has tags, those are listed next it.
  3. The annotations are grouped by color under different headings. However, I also made an ungrouped purely sequential template.
  4. Comments that start with “todo” get formatted into proper tasks.

Benefits of List Callouts

As mentioned, my new approach is to use another plugin by @mgmeyers (yeah, couldn’t get around another plugin), namely List Callouts.

List Callouts stylizes list items based on a single character placed at the beginning of the bullet (like “&” for example). This makes it is a very unobtrusive way to highlight text—unlike using Highlightr.

This offers benefits like:

  • A seamless editing experience. No hidden markdown formatting jumps around when editing the colored highlights, which is great.
  • You can replace the character with an icon of choice. After that, the trigger-character is not visible in Reading mode, Live-preview or Source-mode.
  • Furthermore, you can highlight within highlights, like @tophee mentioned.

Screenshots

Theme: Polka

Initial note state

On the left, you see the initial state of a literature note. Callouts are collapsed, and the annotation category headings are folded (see details on that below), so I can expand them as needed. On the right, you see the metadata callout expanded and the Important heading unfolded, with highlights styled by List Callouts (note the little icons).

Comments and their nested highlights, with tags and tasks:

Here’s how it looks with List Callouts disabled:

“&” is what makes the highlights yellow, under my settings.

Images in callouts

All info callouts expanded

Other improvements and features

  • Better persistence: I improved persistence by having a persistent note section at the start, which is only created on first import, and persists after that (no duplication on update). I purposefully excluded the metadata callout from this persistence, because I want it to update if I make changes in Zotero.
  • Moved status and priority from YAML to inline-dataview fields:
    • Since you can’t persist the YAML, because the persist comments would make the YAML invalid, I moved my status and priority trackers to inline-dataview fields in the persistent notes.
  • The todo hack is compatible with bolding now: Before, I was unable to convert comments starting with “todo” into markdown tasks, while also bolding the comment. This has been fixed.
  • Fixed the following issues with the list:
    • Image comments being duplicated (under the image and as a first level bullet).
    • Post-it comments (without highlights) not having page numbers and tags.
  • Use @apfelstrudelig’s alias snippet from here.
  • Condensed the metadata callout.
  • Added collections as [[links]] in the metadata.
  • Also converted author names to [[links]] in the metadata.
  • Use cursor placeholders from Templater
    • This allows me to quickly edit fields like status and priority after importing.
  • Bold the words Objective, Methodology, Method, Results, Conclusion if they appear in the abstract.
  • Use the Creases plugin to fold the color headings when creating the literature note.
    • This allows me to unfold them as necessary.
    • If you don’t want this feature, remove %% fold %% from the template.
  • Placed images in callouts to make them stand out
    • Alternatively, this also makes them collapsible.
  • Update 2023-06-03 Fixed Bibliographies with numbered styles
    • The fix is to replace line-breaks with a single space.
  • Update 2023-06-05 Added “Citations” callout with query for the current citekey

How it works

To make a template that utilizes List callouts, I made a macro (“calloutCharacter”) similar to the one for creating headings based on colors. But rather than headings, it inserts the right character for each color at the start of each highlight.

It requires some setup to make it work for you! I’ve simplified the setup based on feedback from @galachus. Now, the calloutCharacter macro matches the seven default character/color combos of List callouts—except for magenta (hex: #e56eee), which there is no default List Callout for. All the other colors will work out of the box, if you just install List Callouts and leave it at that.

So, the simplified steps are:

  1. Install and enable List Callouts. Done :tada:

Optionally, you can also:

  1. Create a List Callout type for Magenta (recommended).

    • I’ve set the character for magenta to be in the template. You can either use that in List Callouts’ settings when creating the magenta List Callout type, or choose something else.
    • If you pick a different character for magenta, remember to change it in the template too.
  2. Replace the trigger-characters with icons in List Callouts’ settings (recommended).

    • This will render the characters as icons, as you can see in my screenshots.
  3. Customize which characters should correspond to which List Callout.

    • For example, I use blue highlights for questions, so I picked ? as the character for the blue list callout.

Of course, you should also change the headings to fit your needs in the heading(color) macro.

See this table for reference on which hex code corresponds to which color. This is useful when (optionally) customizing the calloutCharacter macro, and the heading(color) macro:

colorCategory color
Yellow ffd400
Red ff6666
Green 5fb236
Blue 2ea8e5
Purple a28ae5
Magenta e56eee
Orange f19837
Grey aaaaaa

The grouped template

Click the copy button in the upper-right corner of the code block to grab the template.

---
citekey: {{citekey}}
aliases: ["
    {%- if creators -%}
        {{creators[0].lastName}}
        {%- if creators|length > 1 %} et al.{% endif -%}
    {%- endif -%}
    {%- if date %} ({{date | format("YYYY")}}){% endif -%} 
    {%- if shortTitle %} {{shortTitle | safe}} {%- else %} {{title | safe}} {%- endif -%}
"]
title: "{{title}}"
authors: {{authors}}
tags: [literature-note, {% for t in tags %}{{t.tag}}{% if not loop.last %}, {% endif %}{% endfor %}]
year: {{date | format("YYYY")}}
publisher: "{{publicationTitle}}"
doi: {{DOI}}
---

# [{{title}}]({{desktopURI}})

{% persist "notes" %}
{% if isFirstImport %}
## Key takeaways
- <% tp.file.cursor(1) %>

## Processing

- **Status**:: <% tp.file.cursor(2) %>
- **Priority**:: <% tp.file.cursor(3) %>
- **Connections**:: <% tp.file.cursor(4) %>
{% endif %}{% endpersist %}

> [!info]- Info - [**Zotero**]({{desktopURI}}) | [**DOI**](https://doi.org/{{DOI}}) | {% for attachment in attachments | filterby("path", "endswith", ".pdf") %}[**PDF**](file:///{{attachment.path | replace(" ", "%20")}}){%- endfor %}
>
> {% if bibliography %}**Bibliography**: {{bibliography|replace("\n"," ")}}{% endif %}
> 
> **Authors**:: {% for a in creators %} [[{{a.firstName}} {{a.lastName}}]]{% if not loop.last %}, {% endif %}{% endfor %}
> 
> {% if hashTags %}**Tags**: {{hashTags}}{% endif %}
> 
> **Collections**:: {% for collection in collections %}[[{{collection.name}}]]{% if not loop.last %}, {% endif %}{% endfor %}
> 
> **First-page**: {% for annotation in annotations %}{% if loop.first %}{{annotation.pageLabel}}{% endif %}{% endfor %}

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

> [!quote]- Citations
> 
> ```query
> content: "@{{citekey}}" -file:@{{citekey}}
> ```
 
---

## Reading notes
{% macro heading(color) -%}
{%- if color == "#5fb236" -%}
💡 Main ideas and conclusions
{%- endif -%}
{%- if color == "#2ea8e5" -%}
❔ Questions
{%- endif -%}
{%- if color == "#ffd400" -%}
⭐ Important
{%- endif -%}
{%- if color == "#a28ae5" -%}
🧩 Definitions and concepts
{%- endif -%}
{%- if color == "#ff6666" -%}
⛔ Weaknesses and caveats
{%- endif -%}
{%- if color == "#e56eee" -%}
⚡ Hypotheses
{%- endif -%}
{%- if color == "#f19837" -%}
⚙️ Method
{%- endif -%}
{%- if color == "#aaaaaa" -%}
📣 Survey instruments
{%- endif -%}
{%- endmacro -%}

{% macro calloutCharacter(color) -%}
{%- if color == "#5fb236" -%}
$
{%- endif -%}
{%- if color == "#2ea8e5" -%}
@
{%- endif -%}
{%- if color == "#ffd400" -%}
&
{%- endif -%}
{%- if color == "#a28ae5" -%}
~
{%- endif -%}
{%- if color == "#ff6666" -%}
!
{%- endif -%}
{%- if color == "#e56eee" -%}
€
{%- endif -%}
{%- if color == "#f19837" -%}
?
{%- endif -%}
{%- if color == "#aaaaaa" -%}
%
{%- endif -%}
{%- endmacro -%}

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

{% for color, annotations in annotations | groupby("color") -%}

### {{heading(color)}} %% fold %%
{% for annotation in annotations -%}
{%- if annotation.imageRelativePath %}

> [!cite]+ Image [(p. {{annotation.pageLabel}})](zotero://open-pdf/library/items/{{annotation.attachment.itemKey}}?page={{annotation.pageLabel}}&annotation={{annotation.id}})
> ![[{{annotation.imageRelativePath}}]]{% if annotation.hashTags %}
> {{annotation.hashTags}}{% endif %}{%- if (annotation.comment or []).indexOf("todo ") !== -1 %}
> - [ ] **{{annotation.comment | replace("todo ", "")}}**{% else %}
> **{{annotation.comment}}**{%- endif -%}

{% elif (annotation.comment or []).indexOf("todo ") !== -1 %}
- [ ] **{{annotation.comment | replace("todo ", "")}}**:{% if not annotation.annotatedText %} [(p. {{annotation.pageLabel}})](zotero://open-pdf/library/items/{{annotation.attachment.itemKey}}?page={{annotation.pageLabel}}&annotation={{annotation.id}}){% else %}
	- {{calloutCharacter(annotation.color)}} {{annotation.annotatedText | nl2br}} [(p. {{annotation.pageLabel}})](zotero://open-pdf/library/items/{{annotation.attachment.itemKey}}?page={{annotation.pageLabel}}&annotation={{annotation.id}}) {% if annotation.hashTags %}{{annotation.hashTags}}{% endif -%}{% endif -%}
{% elif annotation.comment %}
- **{{annotation.comment}}**:{% if not annotation.annotatedText %} [(p. {{annotation.pageLabel}})](zotero://open-pdf/library/items/{{annotation.attachment.itemKey}}?page={{annotation.pageLabel}}&annotation={{annotation.id}}){% else %}
	- {{calloutCharacter(annotation.color)}} {{annotation.annotatedText | nl2br}} [(p. {{annotation.pageLabel}})](zotero://open-pdf/library/items/{{annotation.attachment.itemKey}}?page={{annotation.pageLabel}}&annotation={{annotation.id}}) {% if annotation.hashTags %}{{annotation.hashTags}}{% endif -%}{% endif %}
{%- elif annotation.annotatedText %}
- {{calloutCharacter(annotation.color)}} {{annotation.annotatedText | nl2br}} [(p. {{annotation.pageLabel}})](zotero://open-pdf/library/items/{{annotation.attachment.itemKey}}?page={{annotation.pageLabel}}&annotation={{annotation.id}}) {% if annotation.hashTags %}{{annotation.hashTags}}{% endif %}
{%- endif -%}{%- endfor %}

{% endfor -%}
{% endif %}
{% endpersist %}

The ungrouped / sequential template

This template simply displays the annotations in one long list in the same sequence they appear in the source. The highlights are colored using List Callouts.

Note that the grouped template is my main focus, so I may not have implemented everything listed in this sequential template. Click the copy button in the upper-right corner of the code block to grab the template.

---
citekey: {{citekey}}
aliases: ["
    {%- if creators -%}
        {{creators[0].lastName}}
        {%- if creators|length > 1 %} et al.{% endif -%}
    {%- endif -%}
    {%- if date %} ({{date | format("YYYY")}}){% endif -%} 
    {%- if shortTitle %} {{shortTitle | safe}} {%- else %} {{title | safe}} {%- endif -%}
"]
title: "{{title}}"
authors: {{authors}}
tags: [literature-note, {% for t in tags %}{{t.tag}}{% if not loop.last %}, {% endif %}{% endfor %}]
year: {{date | format("YYYY")}}
publisher: "{{publicationTitle}}"
doi: {{DOI}}
---

# [{{title}}]({{desktopURI}})

{% persist "notes" %}
{% if isFirstImport %}
## Key takeaways
- <% tp.file.cursor(1) %>

## Processing

- **Status**:: <% tp.file.cursor(2) %>
- **Priority**:: <% tp.file.cursor(3) %>
- **Connections**:: <% tp.file.cursor(4) %>
{% endif %}{% endpersist %}

> [!info]- Info - [**Zotero**]({{desktopURI}}) | [**DOI**](https://doi.org/{{DOI}}) | {% for attachment in attachments | filterby("path", "endswith", ".pdf") %}[**PDF**](file:///{{attachment.path | replace(" ", "%20")}}){%- endfor %}
>
> {% if bibliography %}**Bibliography**: {{bibliography|replace("\n"," ")}}{% endif %}
> 
> **Authors**:: {% for a in creators %} [[{{a.firstName}} {{a.lastName}}]]{% if not loop.last %}, {% endif %}{% endfor %}
> 
> {% if hashTags %}**Tags**: {{hashTags}}{% endif %}
> 
> **Collections**:: {% for collection in collections %}[[{{collection.name}}]]{% if not loop.last %}, {% endif %}{% endfor %}
> 
> **First-page**: {% for annotation in annotations %}{% if loop.first %}{{annotation.pageLabel}}{% endif %}{% endfor %}

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

> [!quote]- Citations
> 
> ```query
> content: "@{{citekey}}" -file:@{{citekey}}
> ```

## Reading notes
{% macro calloutCharacter(color) -%}
{%- if color == "#5fb236" -%}
$
{%- endif -%}
{%- if color == "#2ea8e5" -%}
@
{%- endif -%}
{%- if color == "#ffd400" -%}
&
{%- endif -%}
{%- if color == "#a28ae5" -%}
~
{%- endif -%}
{%- if color == "#ff6666" -%}
!
{%- endif -%}
{%- if color == "#e56eee" -%}
€
{%- endif -%}
{%- if color == "#f19837" -%}
?
{%- endif -%}
{%- if color == "#aaaaaa" -%}
%
{%- endif -%}
{%- endmacro -%}

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

> [!cite]+ Image [(p. {{annotation.pageLabel}})](zotero://open-pdf/library/items/{{annotation.attachment.itemKey}}?page={{annotation.pageLabel}}&annotation={{annotation.id}})
> ![[{{annotation.imageRelativePath}}]]{% if annotation.hashTags %}
> {{annotation.hashTags}}{% endif %}{%- if (annotation.comment or []).indexOf("todo ") !== -1 %}
> - [ ] **{{annotation.comment | replace("todo ", "")}}**{% else %}
> **{{annotation.comment}}**{%- endif %}

{%- elif (annotation.comment or []).indexOf("todo ") !== -1 %}
- [ ] **{{annotation.comment | replace("todo ", "")}}**:{% if not annotation.annotatedText %} [(p. {{annotation.pageLabel}})](zotero://open-pdf/library/items/{{annotation.attachment.itemKey}}?page={{annotation.pageLabel}}&annotation={{annotation.id}}){% else %}
	- {{calloutCharacter(annotation.color)}} {{annotation.annotatedText | nl2br}} [(p. {{annotation.pageLabel}})](zotero://open-pdf/library/items/{{annotation.attachment.itemKey}}?page={{annotation.pageLabel}}&annotation={{annotation.id}}) {% if annotation.hashTags %}{{annotation.hashTags}}{% endif -%}{% endif -%}
{% elif annotation.comment %}
- **{{annotation.comment}}**:{% if not annotation.annotatedText %} [(p. {{annotation.pageLabel}})](zotero://open-pdf/library/items/{{annotation.attachment.itemKey}}?page={{annotation.pageLabel}}&annotation={{annotation.id}}){% else %}
	- {{calloutCharacter(annotation.color)}} {{annotation.annotatedText | nl2br}} [(p. {{annotation.pageLabel}})](zotero://open-pdf/library/items/{{annotation.attachment.itemKey}}?page={{annotation.pageLabel}}&annotation={{annotation.id}}) {% if annotation.hashTags %}{{annotation.hashTags}}{% endif -%}{% endif %}
{%- elif annotation.annotatedText %}
- {{calloutCharacter(annotation.color)}} {{annotation.annotatedText | nl2br}} [(p. {{annotation.pageLabel}})](zotero://open-pdf/library/items/{{annotation.attachment.itemKey}}?page={{annotation.pageLabel}}&annotation={{annotation.id}}) {% if annotation.hashTags %}{{annotation.hashTags}}{% endif %}
{%- endif -%}{%- endfor %}

{% endif %}
{% endpersist %}

Planned enhancements

  • Adopt @apfelstrudelig’s way of creating a custom order of the headings. This would aid processing, as the literature notes are more uniform that way.
  • Perhaps import handwritten / scribbled notes. Don’t know if it’s possible?
  • Perhaps make the macro in a cleaner way.
  • Change the alias so that two authors are separated by “and” rather than suffix the first author with et al…
  • Use colorCategory rather than color to make it easier to adjust and understand the template.

PAQ (Potentially asked questions)

  • What is the todo hack?
    • It’s a way to convert comments that start with “todo” into proper markdown tasks: - [ ]
    • To use it, just write “todo” at the start of comments when annotating, in lowercase. When importing, the comment will be formatted as a task.
    • You can change the following part of the code to have another keyword trigger task formatting. Change both instances of “todo”:
{% elif (annotation.comment or []).indexOf("todo ") !== -1 %}
- [ ] **{{annotation.comment | replace("todo ", "")}}** [...]

Something unclear?

Feel free to let me know if something is unclear or if you are having trouble trying out my template.

If you don’t know how set up Zotero Integration so it can use these templates, check out this explainer by @DannyHatcher: Zotero Obsidian Integration - YouTube

Lists looking too condensed?

I’ve been lucky that the theme I used has a bit more list spacing than some others. For those of you with themes where the List callouts are not sufficiently spaced (Minimal and AnuPpuccin, for example), you change the list spacing using CSS.

To limit the CSS change to your literature notes, you have to use a cssclass. Add this line to the yaml frontmatter of your literature note template: cssclass: literature-note

Then, in the Snippets folder, located in the .obsidian folder, create a CSS file called something like lit-note-lists.css (for example). To make a CSS file, you create a plaintext file, and change the file extension to CSS.

Paste this as the content of the CSS file:

.literature-note {
  --list-spacing: 0.3em; /* default 0.075em; */
}

.literature-note designates that this applies to a CSS class called literature-note. You can change the CSS class name to whatever you like, but the change must be reflected in the frontmatter of the literature note template as well.

After making the CSS snippet in the Snippets folder, the last step is to enable it in Obsidian. Settings → Appearance → Scroll down to snippets, and toggle the snippet on.

If necessary, change the 0.3em value, until you are satisfied with the resulting spacing. It may be necessary to refresh the snippets under Settings → Appearance.

Thanks to @galachus for the CSS snippet above.

6 Likes

Excellent work on this. You’ve hooked me on images in callouts. I think there were a few color/symbol mismatches in the calloutCharacter macro originally, but it seems you fixed that in the templates. I thought I was losing my mind for a moment, thinking “Wait, wasn’t orange here?”

So…

  • , @{{citekey}} is present in the YAML aliases for the ungrouped/chronological template but not the grouped template.

  • The - is missing before the [ ] for the todo hack in the image element.

These may be intentional, causing other issues if changed. They’re just a few things that jumped out at me on first use.

1 Like

After reading all these beautiful templates I decided to put mine here as well. It is slightly simpler then most, but has most of the same functionality.

My main use is block-references. I want to be able to reuse zotero highlights in other notes. For this every annotation, image etc has it’s own (static) id (´^123456´)

Note: if you edit an annotation, the block-id will change!

Supports:

  • Authors clickable
  • Links back to Zotero, so easy to jump back and forth
  • Related items (from zotero) added, both local and zotero
  • Item history, so I can see when I read those papers (linked to dates in my journal)
  • Comments, with their own tags. They are in the same block as the annotations for easy reuse
  • block-ids (^12345) !!!
  • All items are grouped by color
  • Images, with notes and tags (and block-ids)
  • Persistent notes-block
  • NEW persistent annotations

NOTICE: persistent annotations are in the gist version from version 14. It works by creating a persistent block for every individual annotation. For this to work, this template has to be the one creating the page! If a page already exists, rename or remove it. This is a work in progress!!

The papers note:

The annotations linked in another note:

Github gist with the latest version, the gist gets updated, and is already ahead of the version here!

---
title: "{{title | safe}}"
alias: {% if ShortTitle %}"{{shortTitle | safe}}"{% endif %}
Year: {{date | format("YYYY")}}
tags: type/source
Authors: {{authors}}{{directors}}
---
{#- These can be changed -#}
{#- This is the order in which the annotations are ordered -#}
{%-
   set categoryHeading = {
		"orange":  "Main ideas and conclusions",
        "yellow":  "Ordinary notes",
		"blue":    "Quote / quotable",
		"green":   "Important To Me",
		"red":     "Disagree With Author",
        "purple":  "Interesting side-point",
        "magenta": "Methodology",
		"grey":    "Definitions and concepts"
   }
-%}
{%-
    set categoryIcon = {
        "orange": "💡",
        "yellow": "📚",
        "blue": "💬",
        "green": "💚",
        "red": "⛔",
        "purple": "💭",
        "magenta": "⚙️",
        "grey": "🧩"
    }
-%}
{#- ---------- Don't make any changes under here --------- #}
{%- macro minEditDate() -%}
   {%- set tempDate = "" -%}
	{%- for a in annotations -%}
		{%- set testDate = a.date | format("YYYY-MM-DD#HH:mm:ss") -%}
		{%- if testDate < tempDate or tempDate == ""-%}
			{%- set tempDate = testDate -%}
		{%- endif -%}
	{%- endfor -%}
    {%- for a in notes -%}
		{%- set testDate = a.dateModified | format("YYYY-MM-DD#HH:mm:ss") -%}
		{%- if testDate < tempDate or tempDate == ""-%}
			{%- set tempDate = testDate -%}
		{%- endif -%}
	{%- endfor -%}
	{{tempDate }}
{%- endmacro -%}
{# infer latest note date #}
{%- macro maxEditDate() -%}
   {%- set tempDate = "" -%}
	{%- for n in annotations -%}
		{%- set testDate = n.date | format("YYYY-MM-DD#HH:mm:ss") -%}
		{%- if testDate > tempDate or tempDate == ""-%}
			{%- set tempDate = testDate -%}
		{%- endif -%}
	{%- endfor -%}
	{%- for n in notes -%}
		{%- set testDate = n.dateModified | format("YYYY-MM-DD#HH:mm:ss") -%}
		{%- if testDate > tempDate or tempDate == ""-%}
			{%- set tempDate = testDate -%}
		{%- endif -%}
	{%- endfor -%}
	{{tempDate}}
{%- endmacro -%}
{#- handle | characters in zotero strings used in MD -#}
{% macro formatCell(cellText) -%}
{{ cellText | replace("|","❕")}}
{%- endmacro %}
{#- TAGS: handle space characters in zotero tags -#}
{%- set space = joiner(' ') -%} 
{%- macro printTags(rawTags) -%}
	{%- if rawTags.length > 0 -%}
		{%- for tag in rawTags -%}
			#{{ tag.tag | lower | replace(" ","_") }} {{ space() }} 
		{%- endfor -%}
	{%- endif -%}
{%- endmacro %}
{%-
    set zoteroColors = {
        "#ff6666": "red",
        "#f19837": "orange",
        "#5fb236": "green",
        "#ffd400": "yellow",
        "#2ea8e5": "blue",
        "#a28ae5": "purple",
        "#e56eee": "magenta",
        "#aaaaaa": "grey"
    }
-%}

# {{title}}

> [!info]- Info - [**Zotero**]({{desktopURI}}) | [**DOI**](https://doi.org/{{DOI}}) | Local {% for attachment in attachments | filterby("path", "endswith", ".pdf") %}[**PDF**](file:///{{attachment.path | replace(" ", "%20")}}){%- endfor %}
> {% if ShortTitle %}Short title: {{shortTitle | safe}}{% endif %}
> Authors: {% for c in creators %}[[{{c.firstName}} {{c.lastName}}]] {% endfor %} 
> Publication: {{publicationTitle}} 
> Year: {{date | format("YYYY")}}
{% if DOI %}> DOI: **{{DOI}}**{% endif %}
> Zotero links: [Item]({{select}}) {% if pdfZoteroLink %}PDF: {{pdfZoteroLink}}{% endif %} 
> Web links: [Item]({{uri}}) {% if pdfLink %}PDF: {{pdfLink}}{% endif %} 
> {{printTags(note.tags)}}
>
> **History**
> Date item added to Zotero: [[{{dateAdded | format("YYYY-MM-DD")}}]]
> First date annotations or notes modified: [[{{minEditDate() | truncate(10,true,"")}}]]
> Last date annotations or notes modified: [[{{maxEditDate()| truncate(10,true,"")}}]]

{%- if relations.length > 0 %}
{{ "" }}
> [!abstract] Related Zotero items ({{ relations.length}}):  
>
> | title | proxy note | desktopURI |
> | --- | --- | --- |
{%- for r in relations %}
> | {{formatCell(r.title)}} | [[@{{r.citekey}}]] | [Zotero Link]({{r.desktopURI}}) | {% if rel.DOI %}> DOI: {{rel.DOI}}{% endif %} |
{%- endfor -%}
{{ "" }}
{%- endif %}

{% if notes.length > 0 %}
> [!note] Notes ({{notes.length}})
{{ "" }}
{%- for note in notes -%}
{#- Clean up note, change heading level, just in case -#}
> {{ note.note | replace ("# ","### ") }}
> {{printTags(note.tags)}}
> <small>📝️ (modified: {{ note.dateModified | format("YYYY-MM-DD") }}) [link](zotero://select/library/items/{{note.key}}) - [web]({{note.uri}})</small>
>  {{ "" }}
> ---
{% endfor %}
{% endif -%}

> [!abstract]-
> {% if abstractNote %}
> {{abstractNote|replace("\n"," ")}}
> {% endif %}

---
## Persistant notes 
{% persist "notes" %}

{% endpersist %}

---
# Annotations <small>(Exported: [[{{exportDate | format("YYYY-MM-DD")}}]]</small>)

{% for color, colorCategorie in zoteroColors %}
{%- for entry in annotations | filterby ("color", "startswith", color) -%}
{%- if entry.id %}
{%- if entry and loop.first %}## {{categoryIcon[zoteroColors[entry.color]]}} {{categoryHeading[zoteroColors[color]]}}
{% endif -%}
{%- if entry.annotatedText %}{{categoryIcon[zoteroColors[entry.color]]}} {{entry.annotatedText}}
{% endif -%} 
{%- if entry.imageBaseName %}>![[/Assets/@{{citekey}}/{{entry.imageBaseName}}|300]]<br>
{%- endif %}
{%- if entry.comment %}📝️ {{entry.comment}}
{% endif -%}
{{printTags(entry.tags)}} <small>[Page {{entry.page}}](zotero://open-pdf/library/items/{{entry.attachment.itemKey}}?page={{entry.page}}) edited:[[{{ entry.date | format("YYYY-MM-DD")}}]]</small> ^{{ entry.id | lower }}

{% endif -%}
{% endfor -%}
{% endfor -%}

````Preformatted text`
4 Likes

Same here. I can see that the template aims to specify this, but it’s just not translating into the appearance. Not sure why …

Thanks for trying out my template, and especially for the feedback!

  1. The missing dash is definitely an oversight, so you can safely add that. I will update the code above.

  2. The addition of the citekey alias was a last minute change. As I am ambivalent about it, I am not sure if I should remove it in one, or add it to the other. If you want to keep it in yours, you should surround it with quotation marks, otherwise the YAML will be invalid.

  3. However, if you have color/symbol mismatches, then you haven’t fully followed steps 2 and 3:

    1. 2 This means you just have to decide on which characters should correspond to which color, and (optionally) which icon you want to represent the color/character.
    1. Setup the macro in the template (calloutCharacter) so that the color/character combos match List callout’s settings.

My own List Callout settings match the template as shared, because I have changed the characters to suit my preferences. For example, blue means questions to me, so I changed the character for blue list callouts to ?. That’s why I specified those prerequisites for using my template above.

Granted, it would probably be more user-friendly to have the default List Callout character/color combos reflected in the macro. I just assumed people would want to customize which characters correspond to which color/category.

1 Like

Hey,

Thank you for an amazing template. Unfortunately I cannot seem to get it so that metadata such as authors, year, DOI, etc, appear in the “info” section (see photos). Being naive, is there something I am not doing in Zotero to support this?