notion_rails 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca08751cb4669bed3cd0ad791b3242ba6c2f873e3272310750beaa940eb17151
4
- data.tar.gz: fe85cdedfe168e670b5cd2588cb03d514347408ac24396e1dec60e3df8c2bdf6
3
+ metadata.gz: 8b73231a083c06cfc250557a99ad2fb590f704368e301d7c9a59053b03835fcd
4
+ data.tar.gz: 7e2c59c2aa19e4977daa97ae3eef11c829e2322264bd940f0248221e551952d7
5
5
  SHA512:
6
- metadata.gz: '052119acf124d0543367b3bbbc14d762eb08132428f3c1b92242b4069f8f3e8c9665f7fbd1db79f3e5a6915eec853531417853af72096fcd83e18e0fdf39669f'
7
- data.tar.gz: '09a7d8478a722c303e6f22782069dbf74ad83cad14a0949f1fe84453ba4e29dc3703a25de7ab31f4943b6258ab3f5fb471b421f638be2b97f8b780bdbc4533f5'
6
+ metadata.gz: f5643d4e2204fe42e2691c99d9db2ab980fee60e6f21428e75f937a144870b599a64af429fa7488bde0e8ba83db330645330b1eff271eb6f767f8866a64ab573
7
+ data.tar.gz: 88863038b9711c56a55e96e94bb39e681742e7540ab1a62c4535743eca0c6f8bc751366190c459e8aabdc4923dcf5da34775167b8fb777d66d0524ccd7e2c12e
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NotionRails
2
4
  class BaseBlock
3
5
  include NotionRails::Renderers
@@ -58,11 +60,13 @@ module NotionRails
58
60
  when 'heading_2' then render_heading_2(rich_text, class: options[:heading_2])
59
61
  when 'heading_3' then render_heading_3(rich_text, class: options[:heading_3])
60
62
  when 'table_of_contents' then render_table_of_contents
61
- when 'bulleted_list_item' then render_bulleted_list_item(rich_text, @siblings, @children, class: options[:bulleted_list_item])
62
- when 'numbered_list_item' then render_numbered_list_item(rich_text, @siblings, @children, class: options[:numbered_list_item])
63
+ when 'bulleted_list_item'
64
+ render_bulleted_list_item(rich_text, @siblings, @children, class: options[:bulleted_list_item])
65
+ when 'numbered_list_item'
66
+ render_numbered_list_item(rich_text, @siblings, @children, class: options[:numbered_list_item])
63
67
  when 'quote' then render_quote(rich_text, class: options[:quote])
64
68
  when 'callout' then render_callout(rich_text, icon, class: options[:callout])
65
- when 'code' then render_code(rich_text, class: "#{options[:code]} language-#{@properties['language']}")
69
+ when 'code' then render_code(rich_text, class: "#{options[:code]} language-#{@properties["language"]}")
66
70
  when 'image' then render_image(*multi_media)
67
71
  when 'video' then render_video(*multi_media)
68
72
  else
@@ -92,7 +96,6 @@ module NotionRails
92
96
 
93
97
  private
94
98
 
95
- def render_table_of_contents
96
- end
99
+ def render_table_of_contents; end
97
100
  end
98
101
  end
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NotionRails
2
4
  class BasePage
3
5
  include NotionRails::Renderers
6
+
4
7
  # TODO: validate object type is page
5
8
  attr_reader :id,
6
9
  :created_time,
@@ -12,9 +15,11 @@ module NotionRails
12
15
  :parent,
13
16
  :archived,
14
17
  :properties,
18
+ :published_at,
15
19
  :tags,
16
20
  :title,
17
21
  :slug,
22
+ :description,
18
23
  :url
19
24
 
20
25
  def initialize(data)
@@ -41,12 +46,22 @@ module NotionRails
41
46
  render_title(@title, options)
42
47
  end
43
48
 
49
+ def formatted_description(options = {})
50
+ render_paragraph(@description, options)
51
+ end
52
+
53
+ def formatted_published_at(options = {})
54
+ render_date(@published_at, options)
55
+ end
56
+
44
57
  private
45
58
 
46
59
  def process_properties
47
60
  @tags = @properties['tags']
48
61
  @title = @properties.dig('name', 'title')
49
62
  @slug = @properties['slug']
63
+ @published_at = @properties.dig('published', 'date', 'start')
64
+ @description = @properties.dig('description', 'rich_text')
50
65
  end
51
66
  end
52
67
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NotionRails
2
4
  class Page
3
5
  include NotionRails::Renderers
@@ -5,14 +7,16 @@ module NotionRails
5
7
  attr_reader :metadata, :blocks
6
8
 
7
9
  delegate :formatted_title, to: :metadata
10
+ delegate :formatted_description, to: :metadata
11
+ delegate :formatted_published_at, to: :metadata
8
12
 
9
13
  def initialize(base_page, base_blocks)
10
- @metadata = base_page
11
- @blocks = base_blocks
12
- end
14
+ @metadata = base_page
15
+ @blocks = base_blocks
16
+ end
13
17
 
14
- def formatted_blocks(options = {})
15
- @blocks.map { |block| block.render(options) }
16
- end
18
+ def formatted_blocks(options = {})
19
+ @blocks.map { |block| block.render(options) }
20
+ end
17
21
  end
18
22
  end
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'action_view'
4
+
1
5
  module NotionRails
2
6
  module Renderers
3
7
  include ActionView::Helpers::AssetTagHelper
@@ -15,7 +19,7 @@ module NotionRails
15
19
  when 'code'
16
20
  'inline-code' if annotations[key]
17
21
  when 'color'
18
- "text-#{annotations['color']}-600" if annotations[key] != 'default'
22
+ "text-#{annotations["color"]}-600" if annotations[key] != 'default'
19
23
  else
20
24
  annotations[key] ? key : nil
21
25
  end
@@ -23,61 +27,65 @@ module NotionRails
23
27
  classes.compact.join(' ')
24
28
  end
25
29
 
26
- def text_renderer(properties)
30
+ def text_renderer(properties, options = {})
27
31
  properties.map do |rich_text|
28
32
  classes = annotation_to_css_class(rich_text['annotations'])
29
33
  if rich_text['href']
30
34
  link_to(
31
35
  rich_text['plain_text'],
32
36
  rich_text['href'],
33
- class: "link #{classes}"
37
+ class: "link #{classes} #{options[:class]}"
34
38
  )
35
39
  elsif classes.present?
36
- content_tag(:span, rich_text['plain_text'], class: classes)
40
+ content_tag(:span, rich_text['plain_text'], class: "#{classes} #{options[:class]}")
37
41
  else
38
- rich_text['plain_text']
42
+ tag.span(rich_text['plain_text'], class: options[:class])
39
43
  end
40
- end
44
+ end.join('').html_safe
41
45
  end
42
46
 
43
47
  def render_title(title, options = {})
44
- render_paragraph(title, options)
48
+ render_heading_1(title, options)
49
+ end
50
+
51
+ def render_date(date, options = {})
52
+ # TODO: handle end and time zone
53
+ # date=end=, start=2023-07-13, time_zone=, id=%5BsvU, type=date
54
+ tag.p(date.to_date.to_fs(:long), class: options[:class])
45
55
  end
46
56
 
47
57
  def render_paragraph(rich_text_array, options = {})
48
58
  content_tag(:p, options) do
49
- text_renderer(rich_text_array).join('').html_safe
59
+ text_renderer(rich_text_array)
50
60
  end
51
61
  end
52
62
 
53
63
  def render_heading_1(rich_text_array, options = {})
54
- content_tag(:h1, class: 'mb-4 mt-6 text-3xl font-semibold', **options) do
55
- text_renderer(rich_text_array).join('').html_safe
56
- end
64
+ content_tag(:h1, class: 'mb-4 mt-6 text-3xl font-semibold', **options) do
65
+ text_renderer(rich_text_array)
66
+ end
57
67
  end
58
68
 
59
69
  def render_heading_2(rich_text_array, options = {})
60
- content_tag(:h2, class: 'mb-4 mt-6 text-2xl font-semibold', **options) do
61
- text_renderer(rich_text_array).join('').html_safe
62
- end
70
+ content_tag(:h2, class: 'mb-4 mt-6 text-2xl font-semibold', **options) do
71
+ text_renderer(rich_text_array)
72
+ end
63
73
  end
64
74
 
65
75
  def render_heading_3(rich_text_array, options = {})
66
- content_tag(:h3, class: 'mb-2 mt-6 text-xl font-semibold', **options) do
67
- text_renderer(rich_text_array).join('').html_safe
68
- end
76
+ content_tag(:h3, class: 'mb-2 mt-6 text-xl font-semibold', **options) do
77
+ text_renderer(rich_text_array)
78
+ end
69
79
  end
70
80
 
71
81
  def render_code(rich_text_array, options = {})
72
82
  # TODO: render captions
73
83
  pre_options = options
74
- pre_options[:class] = "p-6 rounded #{pre_options[:class]}"
84
+ pre_options[:class] = "border-2 p-6 rounded #{pre_options[:class]}"
75
85
  content_tag(:div, class: 'mt-4', data: { controller: 'highlight' }) do
76
86
  content_tag(:div, data: { highlight_target: 'source' }) do
77
87
  content_tag(:pre, pre_options) do
78
- content_tag(:code, options) do
79
- text_renderer(rich_text_array).join('').html_safe
80
- end
88
+ text_renderer(rich_text_array, options)
81
89
  end
82
90
  end
83
91
  end
@@ -88,7 +96,7 @@ module NotionRails
88
96
  pre_options[:class] = "list-disc break-words #{pre_options[:class]}"
89
97
  content_tag(:ul, pre_options) do
90
98
  content = content_tag(:li, options) do
91
- text_renderer(rich_text_array).join('').html_safe
99
+ text_renderer(rich_text_array)
92
100
  end
93
101
  if children.present?
94
102
  res = children.map do |child|
@@ -110,13 +118,13 @@ module NotionRails
110
118
 
111
119
  def render_list_items(type, rich_text_array, siblings, children, options = {})
112
120
  content = content_tag(:li, options) do
113
- text_renderer(rich_text_array).join('').html_safe
121
+ text_renderer(rich_text_array)
114
122
  end
115
123
  if children.present?
116
- res = children.map do |child|
117
- render_numbered_list_item(child.rich_text, child.siblings, child.children)
118
- end
119
- content += res.join('').html_safe
124
+ res = children.map do |child|
125
+ render_numbered_list_item(child.rich_text, child.siblings, child.children)
126
+ end
127
+ content += res.join('').html_safe
120
128
  end
121
129
  if siblings.present?
122
130
  content += siblings.map do |sibling|
@@ -132,8 +140,10 @@ module NotionRails
132
140
  div_options[:class] = "mt-4 #{options[:class]}"
133
141
  content_tag(:div, div_options) do
134
142
  pre_options[:class] = "border-l-4 border-black px-5 py-1 #{options[:class]}"
135
- content_tag(:cite, pre_options) do
136
- text_renderer(rich_text_array).join('').html_safe
143
+ content_tag(:cite) do
144
+ content_tag(:p, pre_options) do
145
+ text_renderer(rich_text_array)
146
+ end
137
147
  end
138
148
  end
139
149
  end
@@ -143,15 +153,15 @@ module NotionRails
143
153
  pre_options[:class] = "p-4 rounded bg-neutral-200 mt-4 #{pre_options[:class]}"
144
154
  content_tag(:div, pre_options) do
145
155
  content = tag.span(icon, class: 'pr-2')
146
- content += text_renderer(rich_text_array).join('').html_safe
156
+ content += text_renderer(rich_text_array)
147
157
  content
148
158
  end
149
159
  end
150
160
 
151
161
  def render_image(src, expiry_time, caption, type, options = {})
152
162
  content_tag(:figure, options) do
153
- content = tag.img(src:, alt: '')
154
- content += tag.figcaption(text_renderer(caption).join('').html_safe)
163
+ content = tag.img(src: src, alt: '')
164
+ content += tag.figcaption(text_renderer(caption))
155
165
  content
156
166
  end
157
167
  end
@@ -159,11 +169,11 @@ module NotionRails
159
169
  def render_video(src, expiry_time, caption, type, options = {})
160
170
  content_tag(:figure, options) do
161
171
  content = if type == 'file'
162
- video_tag(src, controls: true)
163
- elsif type == 'external'
164
- tag.iframe(src:, allowfullscreen: true, class: 'w-full aspect-video')
165
- end
166
- content += tag.figcaption(text_renderer(caption).join('').html_safe)
172
+ video_tag(src, controls: true)
173
+ elsif type == 'external'
174
+ tag.iframe(src: src, allowfullscreen: true, class: 'w-full aspect-video')
175
+ end
176
+ content += tag.figcaption(text_renderer(caption))
167
177
  content
168
178
  end
169
179
  end
@@ -1,78 +1,77 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NotionRails
2
4
  class Service
3
5
  def initialize
4
- @client = Notion::Client.new
6
+ @client = Notion::Client.new(token: NotionRails.config.notion_api_token)
5
7
  end
6
8
 
7
- def get_articles(tag: nil, slug: nil)
9
+ def default_query(tag: nil, slug: nil)
8
10
  query = [
9
11
  {
10
12
  property: 'public',
11
13
  checkbox: {
12
14
  equals: true
13
15
  }
14
- },
15
- {
16
+ }
17
+ ]
18
+
19
+ if slug
20
+ query.push({
16
21
  property: 'slug',
17
22
  rich_text: {
18
- is_not_empty: true
23
+ equals: slug
19
24
  }
20
- }
21
- ]
25
+ })
26
+ end
22
27
 
23
- query.push({
24
- property: 'slug',
25
- rich_text: {
26
- equals: slug,
27
- }
28
- }) if slug
28
+ if tag
29
+ query.push({
30
+ property: 'tags',
31
+ multi_select: {
32
+ contains: tag
33
+ }
34
+ })
35
+ end
29
36
 
30
- query.push({
31
- property: 'tags',
32
- multi_select: {
33
- contains: tag,
34
- }
35
- }) if tag
37
+ query
38
+ end
36
39
 
37
- pages = @client.database_query(
38
- database_id: Rails.application.credentials.notion.database_id,
39
- sorts: [
40
- {
41
- property: 'published',
42
- direction: 'descending'
43
- }
44
- ],
45
- filter: {
46
- 'and': query
47
- }
48
- )
49
- pages['results'].map { |page| Notion::BasePage.new(page) }
40
+ def default_sorting
41
+ {
42
+ property: 'published',
43
+ direction: 'descending'
44
+ }
45
+ end
46
+
47
+ def get_articles(tag: nil, slug: nil, page_size: 10)
48
+ __get_articles(tag: tag, slug: slug, page_size: page_size)['results'].map do |page|
49
+ NotionRails::BasePage.new(page)
50
+ end
50
51
  end
51
52
 
52
53
  def get_article(id)
53
- base_page = Notion::BasePage.new(@client.page(page_id: id))
54
- base_blocks = get_blocks(id)
55
- Notion::Page.new(base_page, base_blocks)
54
+ base_page = NotionRails::BasePage.new(__get_page(id))
55
+ base_blocks = NotionRails.config.cache_store.fetch(id) { get_blocks(id) }
56
+ NotionRails::Page.new(base_page, base_blocks)
56
57
  end
57
58
 
58
59
  def get_blocks(id)
59
- blocks = @client.block_children(block_id: id)
60
+ blocks = __get_blocks(id)
60
61
  parent_list_block_index = nil
61
62
  results = []
62
63
  blocks['results'].each_with_index do |block, index|
63
- base_block = Notion::BaseBlock.new(block)
64
- if base_block.has_children
65
- base_block.children = get_blocks(base_block.id)
66
- end
64
+ base_block = NotionRails::BaseBlock.new(block)
65
+ base_block.children = get_blocks(base_block.id) if base_block.has_children
67
66
  # Notion returns same list items as different blocks so we have to do some processing to have them be related
68
67
  # TODO: Separate this into a function, add support for bulleted items.
69
68
  # Currently bulleted items render fine, but they do it in separate ul blocks
70
69
  # Make them appear in the same ul block as numbered_items appear in the same ol block
71
70
  if %w[numbered_list_item].include? base_block.type
72
71
  siblings = !parent_list_block_index.nil? &&
73
- index != parent_list_block_index &&
74
- base_block.type == results[parent_list_block_index]&.type &&
75
- base_block.parent == results[parent_list_block_index]&.parent
72
+ index != parent_list_block_index &&
73
+ base_block.type == results[parent_list_block_index]&.type &&
74
+ base_block.parent == results[parent_list_block_index]&.parent
76
75
  if siblings
77
76
  results[parent_list_block_index].siblings << base_block
78
77
  next
@@ -86,5 +85,28 @@ module NotionRails
86
85
  end
87
86
  results
88
87
  end
88
+
89
+ private
90
+
91
+ def __get_articles(tag: nil, slug: nil, page_size: 10)
92
+ @client.database_query(
93
+ database_id: NotionRails.config.notion_database_id,
94
+ sorts: [
95
+ default_sorting
96
+ ],
97
+ filter: {
98
+ 'and': default_query(tag: tag, slug: slug)
99
+ },
100
+ page_size: page_size
101
+ )
102
+ end
103
+
104
+ def __get_page(id)
105
+ @client.page(page_id: id)
106
+ end
107
+
108
+ def __get_blocks(id)
109
+ @client.block_children(block_id: id)
110
+ end
89
111
  end
90
112
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NotionRails
4
- VERSION = "0.1.1"
4
+ VERSION = '0.2.1'
5
5
  end
data/lib/notion_rails.rb CHANGED
@@ -1,3 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "notion_rails/version"
3
+ require 'notion_rails/renderers'
4
+ require 'notion_rails/base_block'
5
+ require 'notion_rails/base_page'
6
+ require 'notion_rails/page'
7
+ require 'notion_rails/service'
8
+ require 'dry-configurable'
9
+
10
+ module NotionRails
11
+ extend Dry::Configurable
12
+
13
+ setting :notion_api_token
14
+ setting :notion_database_id
15
+ setting :cache_store, default: ActiveSupport::Cache::MemoryStore.new
16
+ end
metadata CHANGED
@@ -1,32 +1,74 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: notion_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guillermo Aguirre
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-09 00:00:00.000000000 Z
11
+ date: 2024-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rails
14
+ name: actionview
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 7.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 7.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 7.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
25
39
  - !ruby/object:Gem::Version
26
40
  version: 7.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: dry-configurable
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.2'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: notion-ruby-client
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 1.2.2
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 1.2.2
27
69
  description: Simple gem to render Notion blocks as HTML using Rails
28
70
  email:
29
- - guillermoaguirre1@gmail.com
71
+ - guillermoaguirre@hey.com
30
72
  executables: []
31
73
  extensions: []
32
74
  extra_rdoc_files: []
@@ -46,7 +88,7 @@ licenses:
46
88
  metadata:
47
89
  homepage_uri: https://github.com/guillermoap/notion-rails
48
90
  source_code_uri: https://github.com/guillermoap/notion-rails
49
- post_install_message:
91
+ post_install_message:
50
92
  rdoc_options: []
51
93
  require_paths:
52
94
  - lib
@@ -54,15 +96,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
54
96
  requirements:
55
97
  - - ">="
56
98
  - !ruby/object:Gem::Version
57
- version: 2.6.0
99
+ version: '3.0'
58
100
  required_rubygems_version: !ruby/object:Gem::Requirement
59
101
  requirements:
60
102
  - - ">="
61
103
  - !ruby/object:Gem::Version
62
104
  version: '0'
63
105
  requirements: []
64
- rubygems_version: 3.4.10
65
- signing_key:
106
+ rubygems_version: 3.5.11
107
+ signing_key:
66
108
  specification_version: 4
67
109
  summary: Notion HTML renderer for Rails
68
110
  test_files: []