Skip to content

Latest commit

 

History

History
155 lines (120 loc) · 3.8 KB

README.md

File metadata and controls

155 lines (120 loc) · 3.8 KB

NotionRenderer

This project's author has no affiliation with Notion

Want to render notion API blocks into HTML? This library is for you.

Installation

This package can be installed by adding notion_renderer to your list of dependencies in mix.exs:

def deps do
  [
    {:notion_renderer, "~> 0.1.0"}
  ]
end

TODO

  • Better testing strategy and exhaustive testing
  • Hex documentation (currently documentation is in this file)

Usage

Retrieving blocks via the API is not something this library handles. You need to do that and then provide blocks to NotionRenderer.block_to_html/1,2. In order to render child content, you also need to provide the _children attribute which is a list of blocks. Basically, you can recursively hit the API to build up the blocks list.

Blocks are expected to be a string-based map. The blocks are taken as-is from the API, with the added support of _children.

# Retrieving blocks is up to you
blocks = retrieve_blocks_from_api()

# Then just pass them in!
html = NotionRenderer.block_to_html(blocks)

# or pass options
rewriter = fn href -> "modified #{href}" end
html = NotionRenderer.block_to_html(blocks, [link_rewriter: rewriter])

Options

You can provide link_rewriter option to rewrite all link hrefs. This option is useful to rewrite page links into your platform's patterns.

All of the HTML renderers are replaceable via the config property. It's undocumented at this time.

Dimensions

Notion's API does not provide any dimensional information. So if a video or image has been resized, then there is no access to that in the API. So, it will be max width. It's up to you to style via CSS.

Not supported block types

Have an idea on how to best support these types? Make an issue to discuss:

  • child_page
  • child_database
  • bookmark
  • table_of_contents
  • column
  • column_list
  • link_preview
  • template
  • link_to_page
  • unsupported

Some types are supported but have caveats:

  • bulleted_list_item (is implemented as a ul, does not follow the same display system as Notion)
  • embed (is implemented as a figure containing the source)
  • file (is implemented as a figure containing the source)
  • pdf (is implemented as a figure containing the source)
  • video (is implemented with a few common video providers embed code, but might be missing some. See Html.VideoEmbed for the list)
  • toggle (is implemented, but is just a
      )
    • equation (is implemented, but you must use KaTeX to format it in JS)
    • synced_block (is implemented, but only if you provide the _children property)

    CSS

    Rather than inlining styles, this code tries to use CSS classes whenever reasonable. You can overwrite these classes as needed, but the following stylesheet is a great start.

    <style>
      .notion-callout {
        border-radius: 3px;
        padding: 1rem;
    
        white-space:pre-wrap;
        display:flex;
        gap: 10px;
        background-color: rgba(241, 241, 239, 1);
      }
    
      .notion-callout-content {
        flex-grow: 1;
      }
    
      .notion-video {
        margin: 0;
      }
    
      .notion-embed,
      .notion-file,
      .notion-pdf {
        margin: 1.25em 0;
        page-break-inside: avoid;
      }
    
      .notion-embed .notion-source,
      .notion-file .notion-source,
      .notion-pdf .notion-source {
        border: 1px solid #ddd;
        border-radius: 3px;
        padding: 1.5em;
        word-break: break-all;
      }
    
      .notion-image {
        border: none;
        margin: 1.5em 0;
        padding: 0;
        border-radius: 0;
        text-align: center;
      }
    
      .notion-caption {
        opacity: 0.5;
        font-size: 85%;
        margin-top: 0.5em;
      }
    
      .notion-video-embed-sizer {
        position: relative;
        padding-bottom: calc(9/16 * 100%);
        height: 0;
      }
    
      .notion-video-embed-sizer iframe,
      .notion-video-embed-sizer video {
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        border: 0;
        margin: 0;
      }
    </style>