Core note taking and note management features

Blocks

These features are heavily inspired by Notion , Logseq , Editorjs and the Wordpress block editor .

What are Blocks

Content in a note is organized in units call ‘blocks’. A block can hold any type of content, including text, images, tables, etc. There would be a large number of “built-in” blocks and the possibility for users to create their own block types (see, for example, how Editorjs enables this). Blocks can be nested arbitrarily deep within one another.

Blocks can have attributes and properties. These would be arbitrary key-value pairs, although each block would have some defaults that make sense for that block type (for example, a ‘Done’ property for checklist block lines). See this blog post that explains how Notion manages block attributes and properties. In Notion, attributes are key-value pairs present for every block. Properties are key-value pairs that contain custom attributes for a specific block or block type. Block attributes/properties could show up and be added/edited/deleted in a separate properties panel in the UI, but certain properties could also be added by typing in-line text in the block. For example, the text #tagname# in a block would be used to tag that block with tagname, and the list of tags would be an attribute of the block.

A text note would just be a collection of ordered blocks i.e. a set of blocks appearing in a particular sequence. The same block(s) may appear in other notes (See section Transclusion below). When a block is updated in one note, the updates show up in all other notes where that block appears. (Dendron already has something similar: Note references).

When typing a note, new blocks could be created by typing a sequence of characters that imply “a new block begins here”. The simplest example is that a new block is created simply by pressing the ‘Enter’ key (which is how logseq works by default, although this can be configured in the settings). The type of block could be selected graphically from a dropdown (similar to Wordpress editor) or, even better, the / key can be pressed and that can result in a small dropdown immediately in front of the cursor, from which the type of block can be selected (this is similar to how logseq does it). The default new block type can be a text paragraph.

  • The MVP will focus on blocks that have text content. That text content can be paragraphs, ordered and unordered lists, quotes, checklists etc. #mvp-must-have#
  • The MVP should support blocks with zero, one, or more tags #mvp-must-have#
  • If a block is tagged with a hashtag, clicking on the hashtag should open a note which is populated by a dynamic list of all the blocks tagged with that hashtag #mvp-must-have#
  • Partial text selection across blocks should be possible #mvp-must-have#
    • Currently, with “real” block based tools like Editorjs, Notion etc. it is not possible to select partial text that begins at an arbitrary location in one block and ends at an arbitrary location in another block. What happens is, if even a single character in a block is selected, then all the text in that block ends up getting selected.

Implementation note: Maybe rather than using an actual block editor like Editor.js, it is better to intelligently parse the content of a note and estimate the blocks in it.

Block queries

Since blocks have attributes and properties, it should be possible to query for blocks whose attributes/properties meet a defined criteria. The critera can be specified through a regex or something more user-friendly, or both. The ideal way to make a query should be right in a note. Imagine that the cursor is at the start of a note (or anywhere in the note body, for that matter) and the user types something like “/query foobar”. If that is a well-formed query, the results of the query should appear immediately below, in the note. This is how it works in logseq. For example, typing ‘/query tagname’ (without the ‘’) results in the in-situ text {{query tagname}} and all blocks tagged with tagname appear below the query line. The result is “dynamic” in the sense that if you open a different note, add a new block tagged with tagname, then go back to the earlier note containing {{query tagname}}, then the newly tagged block would appear in the query results.

  • MVP should, at minimum, support querying blocks by hashtags #mvp-must-have#

Bidirectional linking

  • A link to another note, section in a(nother) note, or a block in a(nother) note should be easily created, for example, by typing notations like [[wikilink]] #mvp-must-have#
    • There are some well-established ways to create a link, typically by enclosing with [[]] (()) or {{}} that should be reused. See, for example, the links syntax in Obsidian and Dendron
    • When creating a link, autocomplete suggestions should pop up. The autocomplete suggestions should be continuously refined (pruned) as more letters are typed. #mvp-must-have#
      • See examples of Dendron, Obsidian, logseq
  • At the bottom of each note, there should be a section titled ‘Incoming references’ that lists which other notes link to this note #mvp-must-have#
    • [THINK]: Could this be done for block references? i.e. for each block, show which other blocks (possibly in other notes) link to it? Maybe in a separate pane that shows the block properties?
  • Links must be clickable. Clicking on a link should open the link target note, with cursor at the start of the element in the note that is linked to. Clicking on a link to a non-existing note should create that note. #mvp-must-have#​
  • At the bottom of each note, there should be a section titled ‘Outgoing references’ that lists which other notes are linked to, in this note. #mvp-must-have#
  • At the bottom of each note, in each of the ‘Incoming references’ and ‘Outgoing references’ sections, there should be a subsection titled ‘Unlinked references’ that lists which other notes possibly relate to this note #mvp-nice-to-have#
    • See implementation/documentation in logseq and Obsidian for examples of this
  • Also provide a way to link to sections (identified by Headers) in the same or in other documents.
  • It should be possible to specify the type of link when creating a link. (This is a more advanced feature that needs to be thought out.)

Outlining

  • See features of Dynalist for inspiration https://dynalist.io/features/full
  • Main features to implement earlier are (un)folding of blocks so that all content and child blocks becomes invisible or visible #mvp-must-have#
  • Copying/moving folded blocks should move encapsulated content #mvp-must-have#

Content type

  • Blocks should support text content of various types like paragraphs, ordered and unordered lists, quotes, checklists, code snippets etc. #mvp-must-have#
  • Blocks should support image content in .jpeg, .png formats #mvp-must-have#
  • Images should be resizable #mvp-must-have#
  • The folder in which the images should be stored must be user-configurable, for storage that is not a database (local disk folders) #mvp-must-have#
  • Blocks should support other file types like embedded videos, embeds from YouTube, Vimeo, loom etc.
  • Blocks should support PDF embeds
  • Blocks should support spreadsheet embeds
    • Spreadsheet could be view on a relational database?
  • Blocks should support Math content (e.g. via Mathjax)
  • Blocks should support diagram editor widget (e.g. Excalidraw, draw.io)
    • Logseq supports adding Excalidraw images in a block
  • Blocks should support diagrams drawn with Mermaid syntax

Transclusion

Daily Notes

  • To prevent decision fatigue, the app should have a feature to enable “Daily Notes”. This feature essentially provides a note titled with today’s date, that is presented by default when the app is opened and which can be quickly navigated to with a UI interaction. The user can then jot down their thoughts in the Daily Note, using bidirectional links to other notes. This is how Roam Research and Logseq work.

Hierarchies

  • Notes could be named using the so-called dotted notation that indicates the path in the hierarchical taxonomy of the note. For example: reference.bookmarks.poetry.haiku.md <– This indicates that the note haiku.md is in a hierarchy which has ‘reference’ as the top element, underneath which is ‘bookmarks’, underneath which is ‘poetry’, and finally, ‘haiku’. In many other software, these hierarchical parent elements are folders, but this type of hierarchy is more rigid compared to having all the notes in one and the same folder, just named with dotted notation. The latter is more flexible because it permits “refactoring” the hierarchy with a few simple commands. #mvp-must-have#

  • See the following posts where the creator of another note taking tool, Dendron, went through a similar thought journey and has actually done a good implementation of hierarchical note taking in his tool, Dendron. In sequence,

  • Here is Dendron’s documentation on how it manages hierarchies https://wiki.dendron.so/notes/f3a41725-c5e5-4851-a6ed-5f541054d409.html

  • #THINK# How could we make hierarchies optional, in the spirit of optional.app? If users don’t want to use the dotted notation, and instead define their own folder-and-files structure, that should be possible.

  • Support for fast, fuzzy search i.e. not just the exact search terms, but other results that are close to the search term #mvp-must-have#
    • Results should include notes with the search term in the title as well as note body

Tags

  • Each note, as well as each block within a note, should support zero, one, or more tags. The tags can be created simply by typing ​ #mvp-must-have#​
    • If a tag is in a standalone line in the note, then the tag applies to the entire note.
    • If a tage is in a block, then the tag applies to just that block