Module: NotionToHtml::Renderers

Includes:
ActionView::Context, ActionView::Helpers::AssetTagHelper, ActionView::Helpers::TagHelper, ActionView::Helpers::UrlHelper
Included in:
BaseBlock, BasePage, Page
Defined in:
lib/notion_to_html/renderers.rb

Constant Summary collapse

DEFAULT_CSS_CLASSES =

Default CSS classes for different types of Notion blocks.

{
  bulleted_list_item: 'list-disc list-inside break-words',
  callout: 'flex flex-column p-4 rounded mt-4',
  code: 'border-2 p-6 rounded w-full overflow-x-auto',
  date: '',
  heading_1: 'mb-4 mt-6 text-3xl font-semibold',
  heading_2: 'mb-4 mt-6 text-2xl font-semibold',
  heading_3: 'mb-2 mt-6 text-xl font-semibold',
  image: '',
  numbered_list_item: 'list-decimal list-inside break-words',
  paragraph: '',
  quote: 'border-l-4 border-black px-5 py-1',
  video: 'w-full'
}.freeze

Instance Method Summary collapse

Instance Method Details

#annotation_to_css_class(annotations) ⇒ String

Converts text annotations to corresponding CSS classes.

Parameters:

  • annotations (Hash)

    the annotations hash containing keys like ‘bold’, ‘italic’, ‘color’, etc.

Returns:

  • (String)

    a string of CSS classes.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/notion_to_html/renderers.rb', line 37

def annotation_to_css_class(annotations)
  classes = annotations.keys.map do |key|
    case key
    when 'strikethrough'
      'line-through' if annotations[key]
    when 'bold'
      'font-bold' if annotations[key]
    when 'code'
      'inline-code' if annotations[key]
    when 'color'
      "text-#{annotations["color"]}-600" if annotations[key] != 'default'
    else
      annotations[key] ? key : nil
    end
  end
  classes.compact.join(' ')
end

#render_bulleted_list_item(rich_text_array, siblings, children, parent_index, options = {}) ⇒ String

Renders a bulleted list item.

Parameters:

  • rich_text_array (Array)

    the rich text array containing the content of the list item.

  • _siblings (Array)

    sibling list items.

  • children (Array)

    child list items.

  • options (Hash) (defaults to: {})

    additional options for rendering.

Returns:

  • (String)

    an HTML-safe string with the rendered list item.



84
85
86
87
88
# File 'lib/notion_to_html/renderers.rb', line 84

def render_bulleted_list_item(rich_text_array, siblings, children, parent_index, options = {})
  (:ul, **options, class: css_class_for(:bulleted_list_item, options)) do
    render_list_items(:bulleted_list_item, rich_text_array, siblings, children, parent_index, options)
  end
end

#render_callout(rich_text_array, icon, options = {}) ⇒ String

Renders a callout block.

Parameters:

  • rich_text_array (Array)

    the rich text array containing the content of the callout.

  • icon (String)

    the icon to display in the callout.

  • options (Hash) (defaults to: {})

    additional options for rendering.

Returns:

  • (String)

    an HTML-safe string with the rendered callout.



96
97
98
99
100
101
102
103
104
# File 'lib/notion_to_html/renderers.rb', line 96

def render_callout(rich_text_array, icon, options = {})
  (:div, **options, class: css_class_for(:callout, options)) do
    content = tag.span(icon, class: 'mr-4')
    content += tag.div do
      text_renderer(rich_text_array)
    end
    content
  end
end

#render_code(rich_text_array, options = {}) ⇒ String

Renders a code block.

Parameters:

  • rich_text_array (Array)

    the rich text array containing the code content.

  • options (Hash) (defaults to: {})

    additional options for rendering, including the programming language.

Returns:

  • (String)

    an HTML-safe string with the rendered code block.



111
112
113
114
115
116
117
118
119
120
# File 'lib/notion_to_html/renderers.rb', line 111

def render_code(rich_text_array, options = {})
  # TODO: render captions
  (:div, data: { controller: 'highlight' }) do
    (:div, data: { highlight_target: 'source' }) do
      (:pre, **options, class: "#{css_class_for(:code, options)} language-#{options[:language]}") do
        text_renderer(rich_text_array, options)
      end
    end
  end
end

#render_date(date, options = {}) ⇒ String

Renders a date block.

Parameters:

  • date (Date)

    the date to be rendered.

  • options (Hash) (defaults to: {})

    additional options for rendering.

Returns:

  • (String)

    an HTML-safe string with the rendered date.



127
128
129
130
131
# File 'lib/notion_to_html/renderers.rb', line 127

def render_date(date, options = {})
  # TODO: handle end and time zone
  # date=end=, start=2023-07-13, time_zone=, id=%5BsvU, type=date
  tag.p(date.to_date.to_fs(:long), **options, class: css_class_for(:date, options))
end

#render_heading_1(rich_text_array, options = {}) ⇒ String

Renders a heading 1 block.

Parameters:

  • rich_text_array (Array)

    the rich text array containing the content of the heading.

  • options (Hash) (defaults to: {})

    additional options for rendering.

Returns:

  • (String)

    an HTML-safe string with the rendered heading 1.



138
139
140
141
142
# File 'lib/notion_to_html/renderers.rb', line 138

def render_heading_1(rich_text_array, options = {})
  (:h1, **options, class: css_class_for(:heading_1, options)) do
    text_renderer(rich_text_array)
  end
end

#render_heading_2(rich_text_array, options = {}) ⇒ String

Renders a heading 2 block.

Parameters:

  • rich_text_array (Array)

    the rich text array containing the content of the heading.

  • options (Hash) (defaults to: {})

    additional options for rendering.

Returns:

  • (String)

    an HTML-safe string with the rendered heading 2.



149
150
151
152
153
# File 'lib/notion_to_html/renderers.rb', line 149

def render_heading_2(rich_text_array, options = {})
  (:h2, **options, class: css_class_for(:heading_2, options)) do
    text_renderer(rich_text_array)
  end
end

#render_heading_3(rich_text_array, options = {}) ⇒ String

Renders a heading 3 block.

Parameters:

  • rich_text_array (Array)

    the rich text array containing the content of the heading.

  • options (Hash) (defaults to: {})

    additional options for rendering.

Returns:

  • (String)

    an HTML-safe string with the rendered heading 3.



160
161
162
163
164
# File 'lib/notion_to_html/renderers.rb', line 160

def render_heading_3(rich_text_array, options = {})
  (:h3, **options, class: css_class_for(:heading_3, options)) do
    text_renderer(rich_text_array)
  end
end

#render_image(src, _expiry_time, caption, _type, options = {}) ⇒ String

Renders an image block.

Parameters:

  • src (String)

    the source URL of the image.

  • _expiry_time (Time)

    the expiration time of the image.

  • caption (Array)

    the caption text array for the image.

  • _type (String)

    the type of image (e.g., ‘external’, ‘file’).

  • options (Hash) (defaults to: {})

    additional options for rendering.

Returns:

  • (String)

    an HTML-safe string with the rendered image.



174
175
176
177
178
179
180
# File 'lib/notion_to_html/renderers.rb', line 174

def render_image(src, _expiry_time, caption, _type, options = {})
  (:figure, **options, class: css_class_for(:image, options)) do
    content = tag.img(src: src, alt: '')
    content += tag.figcaption(text_renderer(caption))
    content
  end
end

#render_numbered_list_item(rich_text_array, siblings, children, parent_index, options = {}) ⇒ String

Renders a numbered list item.

Parameters:

  • rich_text_array (Array)

    the rich text array containing the content of the list item.

  • siblings (Array)

    sibling list items.

  • children (Array)

    child list items.

  • options (Hash) (defaults to: {})

    additional options for rendering.

Returns:

  • (String)

    an HTML-safe string with the rendered list item.



189
190
191
192
193
# File 'lib/notion_to_html/renderers.rb', line 189

def render_numbered_list_item(rich_text_array, siblings, children, parent_index, options = {})
  (:ol, **options, class: css_class_for(:numbered_list_item, options)) do
    render_list_items(:numbered_list_item, rich_text_array, siblings, children, parent_index, options)
  end
end

#render_paragraph(rich_text_array, options = {}) ⇒ String

Renders a paragraph block.

Parameters:

  • rich_text_array (Array)

    the rich text array containing the content of the paragraph.

  • options (Hash) (defaults to: {})

    additional options for rendering.

Returns:

  • (String)

    an HTML-safe string with the rendered paragraph.



200
201
202
203
204
# File 'lib/notion_to_html/renderers.rb', line 200

def render_paragraph(rich_text_array, options = {})
  (:p, **options, class: css_class_for(:paragraph, options)) do
    text_renderer(rich_text_array)
  end
end

#render_quote(rich_text_array, options = {}) ⇒ String

Renders a quote block.

Parameters:

  • rich_text_array (Array)

    the rich text array containing the content of the quote.

  • options (Hash) (defaults to: {})

    additional options for rendering.

Returns:

  • (String)

    an HTML-safe string with the rendered quote.



211
212
213
214
215
216
217
218
219
# File 'lib/notion_to_html/renderers.rb', line 211

def render_quote(rich_text_array, options = {})
  (:div, options) do
    (:cite) do
      (:p, **options, class: css_class_for(:quote, options)) do
        text_renderer(rich_text_array)
      end
    end
  end
end

#render_table_of_contents(options = {}) ⇒ String

Renders a table of contents block.

Parameters:

  • options (Hash) (defaults to: {})

    additional options for rendering.

Returns:

  • (String)

    an HTML-safe string with the rendered table of contents.



225
226
227
# File 'lib/notion_to_html/renderers.rb', line 225

def render_table_of_contents(options = {})
  (:p, 'Table of Contents', class: css_class_for(:table_of_contents, options))
end

#render_video(src, _expiry_time, caption, type, options = {}) ⇒ String

Renders a video block.

Parameters:

  • src (String)

    the source URL of the video.

  • _expiry_time (Time)

    the expiration time of the video.

  • caption (Array)

    the caption text array for the video.

  • options (Hash) (defaults to: {})

    additional options for rendering.

Returns:

  • (String)

    an HTML-safe string with the rendered video.



236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/notion_to_html/renderers.rb', line 236

def render_video(src, _expiry_time, caption, type, options = {})
  (:figure, **options, class: css_class_for(:video, options)) do
    content = if type == 'file'
                video_tag(src, controls: true, **options, class: css_class_for(:video, options))
              elsif type == 'external'
                options[:class] = "#{options[:class]} aspect-video"
                tag.iframe(src: src, allowfullscreen: true, **options, class: css_class_for(:video, options))
              end
    content += tag.figcaption(text_renderer(caption))
    content
  end
end

#text_renderer(properties, options = {}) ⇒ String

Renders a rich text property into HTML.

Parameters:

  • properties (Array)

    the rich text array containing text fragments and annotations.

  • options (Hash) (defaults to: {})

    additional options for rendering, such as CSS classes.

Returns:

  • (String)

    an HTML-safe string with the rendered text.



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/notion_to_html/renderers.rb', line 60

def text_renderer(properties, options = {})
  properties.map do |rich_text|
    classes = annotation_to_css_class(rich_text['annotations'])
    if rich_text['href']
      link_to(
        rich_text['plain_text'],
        rich_text['href'],
        class: "link #{classes} #{options[:class]}"
      )
    elsif classes.present?
      (:span, rich_text['plain_text'], class: "#{classes} #{options[:class]}")
    else
      tag.span(rich_text['plain_text'], class: options[:class])
    end
  end.join('').html_safe
end