notion_to_html 1.0.0
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 +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +205 -0
- data/lib/notion_to_html/base_block.rb +131 -0
- data/lib/notion_to_html/base_page.rb +95 -0
- data/lib/notion_to_html/page.rb +35 -0
- data/lib/notion_to_html/renderers.rb +290 -0
- data/lib/notion_to_html/service.rb +172 -0
- data/lib/notion_to_html/version.rb +6 -0
- data/lib/notion_to_html.rb +26 -0
- metadata +122 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5c9fc0703ad943d3ec964a2c1f9eb69750dcbbe49fbd271f2f2f213d290d1e5e
|
4
|
+
data.tar.gz: dfdd2d0f9738e991d90d083898d288dcb0b7019a9415fc82f9d83773ea030262
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fe05f80c2b3e452639a0019ad6d2f215e6953b05e13434cc390b0827a1a3294db07e8f71fac9992ec2cc8d57b8f87ec02e27191d98690c1c29abc91a2a108548
|
7
|
+
data.tar.gz: dd192dd44381b12863c88470fe48b4811b1b3fa57722ae6e8cd1ce2c72daa12ac4ea42207d841fa678cfb8dc91315f3e2e129ab31b38c32fba0bd7ce1301b1a2
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2023 Guillermo Aguirre
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
# NotionToHtml
|
2
|
+
|
3
|
+
NotionToHtml is a Ruby gem designed to integrate Notion with Ruby applications. It provides a set of tools for rendering Notion pages and blocks, allowing you to maintain a database of pages in Notion while rendering them real time in you application with ease.
|
4
|
+
|
5
|
+
Now you can use Notion to publish your pages directly to your Ruby web page with one click.
|
6
|
+
|
7
|
+
## Table of Contents
|
8
|
+
|
9
|
+
- [NotionToHtml](#notiontohtml)
|
10
|
+
- [Table of Contents](#table-of-contents)
|
11
|
+
- [About](#about)
|
12
|
+
- [Installation](#installation)
|
13
|
+
- [Dependencies](#dependencies)
|
14
|
+
- [Setup](#setup)
|
15
|
+
- [Notion Integration](#notion-integration)
|
16
|
+
- [Create your integration in Notion](#create-your-integration-in-notion)
|
17
|
+
- [Get your API secret](#get-your-api-secret)
|
18
|
+
- [Give your integration page permissions](#give-your-integration-page-permissions)
|
19
|
+
- [Configuration](#configuration)
|
20
|
+
- [Usage](#usage)
|
21
|
+
- [Rendering](#rendering)
|
22
|
+
- [Pages](#pages)
|
23
|
+
- [Specific Page](#specific-page)
|
24
|
+
- [Customizing styles](#customizing-styles)
|
25
|
+
- [Overriding default styles](#overriding-default-styles)
|
26
|
+
- [Querying](#querying)
|
27
|
+
- [Filtering](#filtering)
|
28
|
+
- [Sorting](#sorting)
|
29
|
+
- [Examples](#examples)
|
30
|
+
- [Development](#development)
|
31
|
+
- [Contributing](#contributing)
|
32
|
+
- [License](#license)
|
33
|
+
- [Code of Conduct](#code-of-conduct)
|
34
|
+
|
35
|
+
## About
|
36
|
+
|
37
|
+
NotionToHtml allows you to seamlessly integrate Notion pages and blocks into your Ruby application. It provides a set of renderers for various Notion block types, including headings, paragraphs, images, and more. With NotionToHtml, you can easily display and format Notion content in your views.
|
38
|
+
|
39
|
+
You just need to create a database in Notion, integrate it and start writing!
|
40
|
+
|
41
|
+
## Installation
|
42
|
+
|
43
|
+
Add the gem to your application's Gemfile:
|
44
|
+
```bash
|
45
|
+
bundle add notion_to_html
|
46
|
+
```
|
47
|
+
Or install it yourself as:
|
48
|
+
```bash
|
49
|
+
gem install notion_to_html
|
50
|
+
```
|
51
|
+
## Dependencies
|
52
|
+
NotionToHtml uses [tailwindcss](https://tailwindcss.com/) classes to define a default styling that mimics Notion's own styling, so make sure to inlcude it in your application.
|
53
|
+
If you wish to use something else you can always override the default styling provided, see []() for more details.
|
54
|
+
|
55
|
+
## Setup
|
56
|
+
This gem is currently very opinionated on how it expects the Notion database to be defined. If you wish to customize this you can override the methods defined in [NotionToHtml::Service](./lib/notion_to_html/service.rb).
|
57
|
+
|
58
|
+
By default the database should have the following structure:
|
59
|
+

|
60
|
+
|
61
|
+
- _name, description & slug_ as Text
|
62
|
+
- tags as Multi-Select
|
63
|
+
- public as Checkbox
|
64
|
+
- published as Date
|
65
|
+
|
66
|
+
Once you have the database created you will have to setup a Notion Integration, so the Notion API can communicate with your database. For this you will have to follow the [Create Your Integration In Notion](https://developers.notion.com/docs/create-a-notion-integration#create-your-integration-in-notion) tutorial.
|
67
|
+
|
68
|
+
If you wish to just quickly set it up, you can follow the relevant steps below, which are taken from that tutorial.
|
69
|
+
|
70
|
+
### Notion Integration
|
71
|
+
#### Create your integration in Notion
|
72
|
+
The first step to building any integration (internal or public) is to create a new integration in Notion’s integrations dashboard: <https://www.notion.com/my-integrations>.
|
73
|
+
1. Click `+ New Integration`.
|
74
|
+

|
75
|
+
2. Enter the integration name and select the associated workspace for the new integration.
|
76
|
+

|
77
|
+
|
78
|
+
#### Get your API secret
|
79
|
+
API requests require an API secret to be successfully authenticated.
|
80
|
+
1. Visit the Configuration tab to get your integration’s API secret (or “Internal Integration Secret”).
|
81
|
+

|
82
|
+
**Remember to keep your API secret a secret!**
|
83
|
+
Any value used to authenticate API requests should always be kept secret. Use environment variables and avoid committing sensitive data to your version control history.
|
84
|
+
If you do accidentally expose it, remember to “refresh” your secret.
|
85
|
+
|
86
|
+
#### Give your integration page permissions
|
87
|
+
The database that we’re about to create will be added to a parent Notion page in your workspace. For your integration to interact with the page, it needs explicit permission to read/write to that specific Notion page.
|
88
|
+
|
89
|
+
To give the integration permission, you will need to:
|
90
|
+
1. Go to the page with the database you created above.
|
91
|
+
2. Click on the ... More menu in the top-right corner of the page.
|
92
|
+
3. Scroll down to + Add Connections.
|
93
|
+
4. Search for your integration and select it.
|
94
|
+
5. Confirm the integration can access the page and all of its child pages.
|
95
|
+

|
96
|
+
6. You can then limit the integrations permission to just `Read Contents`:
|
97
|
+

|
98
|
+
|
99
|
+
Now you're finally ready to config the gem!
|
100
|
+
|
101
|
+
### Configuration
|
102
|
+
To configure NotionToHtml, you need to set up your Notion API token and database ID.
|
103
|
+
If you're using Rails add an initializer file in your Rails application, such as `config/initializers/notion_to_html.rb`, and include the following configuration block:
|
104
|
+
```ruby
|
105
|
+
NotionToHtml.configure do |config|
|
106
|
+
config.notion_api_token = 'NOTION_API_TOKEN'
|
107
|
+
config.notion_database_id = 'NOTION_DATABASE_ID'
|
108
|
+
end
|
109
|
+
```
|
110
|
+
|
111
|
+
To get these values:
|
112
|
+
1. The NOTION_API_TOKEN is the same one from [the setup](#get-your-api-secret).
|
113
|
+
2. To get the NOTION_DATABASE_ID, locate the 32-character string at the end of the page’s URL.
|
114
|
+
```bash
|
115
|
+
https://www.notion.so/myworkspace/a8aec43384f447ed84390e8e42c2e089?v=...
|
116
|
+
|--------- Database ID --------|
|
117
|
+
```
|
118
|
+
|
119
|
+
**Remember to keep these values secret!**
|
120
|
+
|
121
|
+
Now you should be all setup!
|
122
|
+
|
123
|
+
## Usage
|
124
|
+
### Rendering
|
125
|
+
#### Pages
|
126
|
+
To get and render a preview of the pages of your database:
|
127
|
+
```ruby
|
128
|
+
<% NotionToHtml::Service.get_pages.each do |page| %>
|
129
|
+
<%= article.formatted_published_at %>
|
130
|
+
<%= article.id %>
|
131
|
+
<%= article.formatted_title %>
|
132
|
+
<%= article.formatted_description %>
|
133
|
+
<% end %>
|
134
|
+
```
|
135
|
+
#### Specific Page
|
136
|
+
To get and render a specific page:
|
137
|
+
```ruby
|
138
|
+
<% page = NotionToHtml::Service.get_page(page_id) %>
|
139
|
+
<%= page.formatted_title %>
|
140
|
+
<%= page.formatted_published_at %>
|
141
|
+
<% page.formatted_blocks.each do |block| %>
|
142
|
+
<%= block %>
|
143
|
+
<% end %>
|
144
|
+
```
|
145
|
+
#### Customizing styles
|
146
|
+
NotionToHtml ships with default css classes for each supported block. You can add your own set of styling on top by specifying the `class:` option when calling the formatter:
|
147
|
+
```ruby
|
148
|
+
NotionToHtml::Service.get_page(page_id)
|
149
|
+
.formatted_title(class: 'text-4xl md:text-5xl font-bold')
|
150
|
+
```
|
151
|
+
You can also specify classes for each type of supported block like this:
|
152
|
+
```ruby
|
153
|
+
NotionToHtml::Service.get_page(page_id).formatted_blocks(
|
154
|
+
paragraph: 'text-lg',
|
155
|
+
heading_1: 'text-3xl md:text-4xl font-bold',
|
156
|
+
heading_2: 'text-white',
|
157
|
+
heading_3: 'font-bold',
|
158
|
+
quote: 'italic',
|
159
|
+
)
|
160
|
+
```
|
161
|
+
#### Overriding default styles
|
162
|
+
If you feel like you want a clean slate regarding styling you can override the provided default styles by setting the `override_class` option to `true`:
|
163
|
+
```ruby
|
164
|
+
NotionToHtml::Service.get_page(page_id)
|
165
|
+
.formatted_title(class: 'font-bold', override_class: true)
|
166
|
+
```
|
167
|
+
It also works for `formatted_blocks`:
|
168
|
+
```ruby
|
169
|
+
NotionToHtml::Service.get_page(page_id)
|
170
|
+
.formatted_blocks(
|
171
|
+
paragraph: { class: 'text-lg', override_class: true },
|
172
|
+
quote: 'italic'
|
173
|
+
)
|
174
|
+
```
|
175
|
+
### Querying
|
176
|
+
By default the `NotionToHtml::Service` is setup to follow the database structure sepcified above. This way it will only return pages that have been marked as `public`.
|
177
|
+
|
178
|
+
#### Filtering
|
179
|
+
You can filter the results by specifying a tag and/or a specific slug:
|
180
|
+
```ruby
|
181
|
+
NotionToHtml::Service.get_pages(tag: 'web', slug: 'test-slug')
|
182
|
+
```
|
183
|
+
#### Sorting
|
184
|
+
The default sorting is by the `published` Date column in the database
|
185
|
+
|
186
|
+
### Examples
|
187
|
+
To see how the default renderings of the supported blocks look, go over to the [examples](/examples/).
|
188
|
+
|
189
|
+
## Development
|
190
|
+
|
191
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
192
|
+
|
193
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
194
|
+
|
195
|
+
## Contributing
|
196
|
+
|
197
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/guillermoaguirre1@gmail.com/notion_to_html. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](/CODE_OF_CONDUCT.md).
|
198
|
+
|
199
|
+
## License
|
200
|
+
|
201
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
202
|
+
|
203
|
+
## Code of Conduct
|
204
|
+
|
205
|
+
Everyone interacting in the Notion::Rails project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](/CODE_OF_CONDUCT.md).
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The NotionToHtml::BaseBlock class represents a block in a Notion page, handling its attributes and rendering.
|
4
|
+
# This class processes the raw data of a block fetched from the Notion API and makes
|
5
|
+
# it accessible through various attributes. It also provides methods to render formatted
|
6
|
+
# output for different block types like paragraphs, headings, lists, quotes, and media.
|
7
|
+
|
8
|
+
module NotionToHtml
|
9
|
+
class BaseBlock
|
10
|
+
include NotionToHtml::Renderers
|
11
|
+
|
12
|
+
# @return [String] the ID of the block.
|
13
|
+
attr_reader :id
|
14
|
+
# @return [String] the creation timestamp of the block.
|
15
|
+
attr_reader :created_time
|
16
|
+
# @return [String] the last edited timestamp of the block.
|
17
|
+
attr_reader :last_edited_time
|
18
|
+
# @return [String] the user who created the block.
|
19
|
+
attr_reader :created_by
|
20
|
+
# @return [String] the user who last edited the block.
|
21
|
+
attr_reader :last_edited_by
|
22
|
+
# @return [Hash] the parent of the block (e.g., page ID).
|
23
|
+
attr_reader :parent
|
24
|
+
# @return [Boolean] whether the block is archived.
|
25
|
+
attr_reader :archived
|
26
|
+
# @return [Boolean] whether the block has children.
|
27
|
+
attr_reader :has_children
|
28
|
+
# @return [String] the type of the block (e.g., 'paragraph', 'heading_1').
|
29
|
+
attr_reader :type
|
30
|
+
# @return [Hash] the properties of the block, specific to its type.
|
31
|
+
attr_reader :properties
|
32
|
+
|
33
|
+
# @return [Array<BaseBlock>] the children blocks of this block.
|
34
|
+
attr_accessor :children
|
35
|
+
# @return [Array<BaseBlock>] the sibling blocks of this block.
|
36
|
+
attr_accessor :siblings
|
37
|
+
|
38
|
+
# The list of block types that can be rendered.
|
39
|
+
BLOCK_TYPES = %w[
|
40
|
+
paragraph
|
41
|
+
heading_1
|
42
|
+
heading_2
|
43
|
+
heading_3
|
44
|
+
bulleted_list_item
|
45
|
+
numbered_list_item
|
46
|
+
quote
|
47
|
+
callout
|
48
|
+
code
|
49
|
+
image
|
50
|
+
embed
|
51
|
+
video
|
52
|
+
].freeze
|
53
|
+
|
54
|
+
# Initializes a new BaseBlock object.
|
55
|
+
# @param data [Hash] The raw data of the block from the Notion API.
|
56
|
+
def initialize(data)
|
57
|
+
@id = data['id']
|
58
|
+
@created_time = data['created_time']
|
59
|
+
@last_edited_time = data['last_edited_time']
|
60
|
+
@created_by = data['created_by'] # TODO: handle user object
|
61
|
+
@last_edited_by = data['last_edited_by'] # TODO: handle user object
|
62
|
+
@parent = data['parent'] # TODO: handle page_id type
|
63
|
+
@archived = data['archived']
|
64
|
+
@has_children = data['has_children']
|
65
|
+
@children = []
|
66
|
+
@siblings = []
|
67
|
+
@type = data['type']
|
68
|
+
@properties = data[@type]
|
69
|
+
end
|
70
|
+
|
71
|
+
# Renders the block based on its type.
|
72
|
+
# @param options [Hash] Additional options for rendering the block.
|
73
|
+
# @return [String] The rendered block as HTML.
|
74
|
+
def render(options = {})
|
75
|
+
case @type
|
76
|
+
when 'paragraph'
|
77
|
+
render_paragraph(rich_text, class: options[:paragraph])
|
78
|
+
when 'heading_1'
|
79
|
+
render_heading_1(rich_text, class: options[:heading_1])
|
80
|
+
when 'heading_2'
|
81
|
+
render_heading_2(rich_text, class: options[:heading_2])
|
82
|
+
when 'heading_3'
|
83
|
+
render_heading_3(rich_text, class: options[:heading_3])
|
84
|
+
when 'table_of_contents'
|
85
|
+
render_table_of_contents
|
86
|
+
when 'bulleted_list_item'
|
87
|
+
render_bulleted_list_item(rich_text, @siblings, @children, 0, class: options[:bulleted_list_item])
|
88
|
+
when 'numbered_list_item'
|
89
|
+
render_numbered_list_item(rich_text, @siblings, @children, 0, class: options[:numbered_list_item])
|
90
|
+
when 'quote'
|
91
|
+
render_quote(rich_text, class: options[:quote])
|
92
|
+
when 'callout'
|
93
|
+
render_callout(rich_text, icon, class: options[:callout])
|
94
|
+
when 'code'
|
95
|
+
render_code(rich_text, class: options[:code], language: @properties['language'])
|
96
|
+
when 'image', 'embed'
|
97
|
+
render_image(*multi_media, class: options[:image])
|
98
|
+
when 'video'
|
99
|
+
render_video(*multi_media, class: options[:video])
|
100
|
+
else
|
101
|
+
'Unsupported block'
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Retrieves the rich text content of the block.
|
106
|
+
# @return [Array<Hash>] The rich text content.
|
107
|
+
def rich_text
|
108
|
+
@properties['rich_text'] || []
|
109
|
+
end
|
110
|
+
|
111
|
+
# Retrieves the icon associated with the block.
|
112
|
+
# @return [Array<Hash>] The icon data.
|
113
|
+
def icon
|
114
|
+
icon = @properties['icon']
|
115
|
+
@properties['icon'][icon['type']] || []
|
116
|
+
end
|
117
|
+
|
118
|
+
# Retrieves the multimedia data for the block.
|
119
|
+
# @return [Array] The multimedia data (URL, expiry time, caption, type).
|
120
|
+
def multi_media
|
121
|
+
case @properties['type']
|
122
|
+
when 'file'
|
123
|
+
[@properties.dig('file', 'url'), @properties.dig('file', 'expiry_time'), @properties['caption'], 'file']
|
124
|
+
when 'external'
|
125
|
+
[@properties.dig('external', 'url'), nil, @properties['caption'], 'external']
|
126
|
+
else
|
127
|
+
[@properties['url'], nil, @properties['caption'], nil]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The NotionToHtml::BasePage class represents a Notion page, handling its attributes and rendering.
|
4
|
+
# This class processes the raw data of a page fetched from the Notion API and makes
|
5
|
+
# it accessible through various attributes. It also provides methods to render formatted
|
6
|
+
# output for the page's title, description, and published date.
|
7
|
+
|
8
|
+
module NotionToHtml
|
9
|
+
class BasePage
|
10
|
+
include NotionToHtml::Renderers
|
11
|
+
|
12
|
+
# @return [String] the ID of the page.
|
13
|
+
attr_reader :id
|
14
|
+
# @return [String] the creation timestamp of the page.
|
15
|
+
attr_reader :created_time
|
16
|
+
# @return [String] the last edited timestamp of the page.
|
17
|
+
attr_reader :last_edited_time
|
18
|
+
# @return [String] the user who created the page.
|
19
|
+
attr_reader :created_by
|
20
|
+
# @return [String] the user who last edited the page.
|
21
|
+
attr_reader :last_edited_by
|
22
|
+
# @return [Hash, nil] the cover image of the page.
|
23
|
+
attr_reader :cover
|
24
|
+
# @return [Hash, nil] the icon of the page.
|
25
|
+
attr_reader :icon
|
26
|
+
# @return [Hash] the parent of the page (e.g., database ID).
|
27
|
+
attr_reader :parent
|
28
|
+
# @return [Boolean] whether the page is archived.
|
29
|
+
attr_reader :archived
|
30
|
+
# @return [Hash] the properties of the page.
|
31
|
+
attr_reader :properties
|
32
|
+
# @return [String, nil] the publication date of the page.
|
33
|
+
attr_reader :published_at
|
34
|
+
# @return [Array<Hash>, nil] the tags associated with the page.
|
35
|
+
attr_reader :tags
|
36
|
+
# @return [Array<Hash>, nil] the title of the page.
|
37
|
+
attr_reader :title
|
38
|
+
# @return [String, nil] the slug of the page.
|
39
|
+
attr_reader :slug
|
40
|
+
# @return [Array<Hash>, nil] the description of the page.
|
41
|
+
attr_reader :description
|
42
|
+
# @return [String] the URL of the page.
|
43
|
+
attr_reader :url
|
44
|
+
|
45
|
+
# Initializes a new BasePage object.
|
46
|
+
# @param data [Hash] The raw data of the page from the Notion API.
|
47
|
+
def initialize(data)
|
48
|
+
@id = data['id']
|
49
|
+
@created_time = data['created_time']
|
50
|
+
@last_edited_time = data['last_edited_time']
|
51
|
+
@created_by = data['created_by'] # TODO: handle user object
|
52
|
+
@last_edited_by = data['last_edited_by'] # TODO: handle user object
|
53
|
+
@cover = data['cover'] # TODO: handle external type
|
54
|
+
@icon = data['icon'] # TODO: handle emoji type
|
55
|
+
@parent = data['parent'] # TODO: handle database_id type
|
56
|
+
@archived = data['archived']
|
57
|
+
@properties = data['properties'] # TODO: handle properties object
|
58
|
+
process_properties
|
59
|
+
@url = data['url']
|
60
|
+
end
|
61
|
+
|
62
|
+
# Renders the formatted title of the page.
|
63
|
+
# @param options [Hash] Additional options for rendering the title.
|
64
|
+
# @return [String] The formatted title.
|
65
|
+
def formatted_title(options = {})
|
66
|
+
render_heading_1(@title, options)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Renders the formatted description of the page.
|
70
|
+
# @param options [Hash] Additional options for rendering the description.
|
71
|
+
# @return [String] The formatted description.
|
72
|
+
def formatted_description(options = {})
|
73
|
+
render_paragraph(@description, options)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Renders the formatted publication date of the page.
|
77
|
+
# @param options [Hash] Additional options for rendering the publication date.
|
78
|
+
# @return [String] The formatted publication date.
|
79
|
+
def formatted_published_at(options = {})
|
80
|
+
render_date(@published_at, options)
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
# Processes the properties of the page and assigns them to the relevant attributes.
|
86
|
+
# @return [void]
|
87
|
+
def process_properties
|
88
|
+
@tags = @properties['tags']
|
89
|
+
@title = @properties.dig('name', 'title')
|
90
|
+
@slug = @properties['slug']
|
91
|
+
@published_at = @properties.dig('published', 'date', 'start')
|
92
|
+
@description = @properties.dig('description', 'rich_text')
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The NotionToHtml::Page class represents a Notion page, containing both the metadata and blocks associated with the page.
|
4
|
+
# This class integrates metadata and blocks, providing methods to format and render the page's content.
|
5
|
+
|
6
|
+
module NotionToHtml
|
7
|
+
class Page
|
8
|
+
include NotionToHtml::Renderers
|
9
|
+
|
10
|
+
# @return [BasePage] The metadata of the page, encapsulating details like title, description, and published date.
|
11
|
+
attr_reader :metadata
|
12
|
+
# @return [Array<BaseBlock>] The blocks of the page, representing the content sections.
|
13
|
+
attr_reader :blocks
|
14
|
+
|
15
|
+
# Delegate methods to metadata for easy access to formatted title, description, and published date.
|
16
|
+
delegate :formatted_title, to: :metadata
|
17
|
+
delegate :formatted_description, to: :metadata
|
18
|
+
delegate :formatted_published_at, to: :metadata
|
19
|
+
|
20
|
+
# Initializes a new Page object.
|
21
|
+
# @param base_page [BasePage] The metadata of the page.
|
22
|
+
# @param base_blocks [Array<BaseBlock>] The blocks of the page.
|
23
|
+
def initialize(base_page, base_blocks)
|
24
|
+
@metadata = base_page
|
25
|
+
@blocks = base_blocks
|
26
|
+
end
|
27
|
+
|
28
|
+
# Formats and renders the blocks of the page.
|
29
|
+
# @param options [Hash] Additional options for rendering the blocks.
|
30
|
+
# @return [Array<String>] The rendered blocks as an array of HTML strings.
|
31
|
+
def formatted_blocks(options = {})
|
32
|
+
@blocks.map { |block| block.render(options) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,290 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'action_view'
|
4
|
+
|
5
|
+
# The NotionToHtml::Renderers module provides functionality for rendering Notion content
|
6
|
+
# into HTML format. It includes various helper methods from ActionView to assist
|
7
|
+
# in rendering different Notion blocks like paragraphs, headings, lists, images,
|
8
|
+
# and more.
|
9
|
+
|
10
|
+
module NotionToHtml
|
11
|
+
module Renderers
|
12
|
+
include ActionView::Helpers::AssetTagHelper
|
13
|
+
include ActionView::Helpers::TagHelper
|
14
|
+
include ActionView::Helpers::UrlHelper
|
15
|
+
include ActionView::Context
|
16
|
+
|
17
|
+
# Default CSS classes for different types of Notion blocks.
|
18
|
+
DEFAULT_CSS_CLASSES = {
|
19
|
+
bulleted_list_item: 'list-disc list-inside break-words',
|
20
|
+
callout: 'flex flex-column p-4 rounded mt-4',
|
21
|
+
code: 'border-2 p-6 rounded w-full overflow-x-auto',
|
22
|
+
date: '',
|
23
|
+
heading_1: 'mb-4 mt-6 text-3xl font-semibold',
|
24
|
+
heading_2: 'mb-4 mt-6 text-2xl font-semibold',
|
25
|
+
heading_3: 'mb-2 mt-6 text-xl font-semibold',
|
26
|
+
image: '',
|
27
|
+
numbered_list_item: 'list-decimal list-inside break-words',
|
28
|
+
paragraph: '',
|
29
|
+
quote: 'border-l-4 border-black px-5 py-1',
|
30
|
+
video: 'w-full'
|
31
|
+
}.freeze
|
32
|
+
|
33
|
+
# Converts text annotations to corresponding CSS classes.
|
34
|
+
#
|
35
|
+
# @param annotations [Hash] the annotations hash containing keys like 'bold', 'italic', 'color', etc.
|
36
|
+
# @return [String] a string of CSS classes.
|
37
|
+
def annotation_to_css_class(annotations)
|
38
|
+
classes = annotations.keys.map do |key|
|
39
|
+
case key
|
40
|
+
when 'strikethrough'
|
41
|
+
'line-through' if annotations[key]
|
42
|
+
when 'bold'
|
43
|
+
'font-bold' if annotations[key]
|
44
|
+
when 'code'
|
45
|
+
'inline-code' if annotations[key]
|
46
|
+
when 'color'
|
47
|
+
"text-#{annotations["color"]}-600" if annotations[key] != 'default'
|
48
|
+
else
|
49
|
+
annotations[key] ? key : nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
classes.compact.join(' ')
|
53
|
+
end
|
54
|
+
|
55
|
+
# Renders a rich text property into HTML.
|
56
|
+
#
|
57
|
+
# @param properties [Array] the rich text array containing text fragments and annotations.
|
58
|
+
# @param options [Hash] additional options for rendering, such as CSS classes.
|
59
|
+
# @return [String] an HTML-safe string with the rendered text.
|
60
|
+
def text_renderer(properties, options = {})
|
61
|
+
properties.map do |rich_text|
|
62
|
+
classes = annotation_to_css_class(rich_text['annotations'])
|
63
|
+
if rich_text['href']
|
64
|
+
link_to(
|
65
|
+
rich_text['plain_text'],
|
66
|
+
rich_text['href'],
|
67
|
+
class: "link #{classes} #{options[:class]}"
|
68
|
+
)
|
69
|
+
elsif classes.present?
|
70
|
+
content_tag(:span, rich_text['plain_text'], class: "#{classes} #{options[:class]}")
|
71
|
+
else
|
72
|
+
tag.span(rich_text['plain_text'], class: options[:class])
|
73
|
+
end
|
74
|
+
end.join('').html_safe
|
75
|
+
end
|
76
|
+
|
77
|
+
# Renders a bulleted list item.
|
78
|
+
#
|
79
|
+
# @param rich_text_array [Array] the rich text array containing the content of the list item.
|
80
|
+
# @param _siblings [Array] sibling list items.
|
81
|
+
# @param children [Array] child list items.
|
82
|
+
# @param options [Hash] additional options for rendering.
|
83
|
+
# @return [String] an HTML-safe string with the rendered list item.
|
84
|
+
def render_bulleted_list_item(rich_text_array, siblings, children, parent_index, options = {})
|
85
|
+
content_tag(:ul, **options, class: css_class_for(:bulleted_list_item, options)) do
|
86
|
+
render_list_items(:bulleted_list_item, rich_text_array, siblings, children, parent_index, options)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Renders a callout block.
|
91
|
+
#
|
92
|
+
# @param rich_text_array [Array] the rich text array containing the content of the callout.
|
93
|
+
# @param icon [String] the icon to display in the callout.
|
94
|
+
# @param options [Hash] additional options for rendering.
|
95
|
+
# @return [String] an HTML-safe string with the rendered callout.
|
96
|
+
def render_callout(rich_text_array, icon, options = {})
|
97
|
+
content_tag(:div, **options, class: css_class_for(:callout, options)) do
|
98
|
+
content = tag.span(icon, class: 'mr-4')
|
99
|
+
content += tag.div do
|
100
|
+
text_renderer(rich_text_array)
|
101
|
+
end
|
102
|
+
content
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Renders a code block.
|
107
|
+
#
|
108
|
+
# @param rich_text_array [Array] the rich text array containing the code content.
|
109
|
+
# @param options [Hash] additional options for rendering, including the programming language.
|
110
|
+
# @return [String] an HTML-safe string with the rendered code block.
|
111
|
+
def render_code(rich_text_array, options = {})
|
112
|
+
# TODO: render captions
|
113
|
+
content_tag(:div, data: { controller: 'highlight' }) do
|
114
|
+
content_tag(:div, data: { highlight_target: 'source' }) do
|
115
|
+
content_tag(:pre, **options, class: "#{css_class_for(:code, options)} language-#{options[:language]}") do
|
116
|
+
text_renderer(rich_text_array, options)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Renders a date block.
|
123
|
+
#
|
124
|
+
# @param date [Date] the date to be rendered.
|
125
|
+
# @param options [Hash] additional options for rendering.
|
126
|
+
# @return [String] an HTML-safe string with the rendered date.
|
127
|
+
def render_date(date, options = {})
|
128
|
+
# TODO: handle end and time zone
|
129
|
+
# date=end=, start=2023-07-13, time_zone=, id=%5BsvU, type=date
|
130
|
+
tag.p(date.to_date.to_fs(:long), class: css_class_for(:date, options))
|
131
|
+
end
|
132
|
+
|
133
|
+
# Renders a heading 1 block.
|
134
|
+
#
|
135
|
+
# @param rich_text_array [Array] the rich text array containing the content of the heading.
|
136
|
+
# @param options [Hash] additional options for rendering.
|
137
|
+
# @return [String] an HTML-safe string with the rendered heading 1.
|
138
|
+
def render_heading_1(rich_text_array, options = {})
|
139
|
+
content_tag(:h1, **options, class: css_class_for(:heading_1, options)) do
|
140
|
+
text_renderer(rich_text_array)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Renders a heading 2 block.
|
145
|
+
#
|
146
|
+
# @param rich_text_array [Array] the rich text array containing the content of the heading.
|
147
|
+
# @param options [Hash] additional options for rendering.
|
148
|
+
# @return [String] an HTML-safe string with the rendered heading 2.
|
149
|
+
def render_heading_2(rich_text_array, options = {})
|
150
|
+
content_tag(:h2, **options, class: css_class_for(:heading_2, options)) do
|
151
|
+
text_renderer(rich_text_array)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Renders a heading 3 block.
|
156
|
+
#
|
157
|
+
# @param rich_text_array [Array] the rich text array containing the content of the heading.
|
158
|
+
# @param options [Hash] additional options for rendering.
|
159
|
+
# @return [String] an HTML-safe string with the rendered heading 3.
|
160
|
+
def render_heading_3(rich_text_array, options = {})
|
161
|
+
content_tag(:h3, **options, class: css_class_for(:heading_3, options)) do
|
162
|
+
text_renderer(rich_text_array)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# Renders an image block.
|
167
|
+
#
|
168
|
+
# @param src [String] the source URL of the image.
|
169
|
+
# @param _expiry_time [Time] the expiration time of the image.
|
170
|
+
# @param caption [Array] the caption text array for the image.
|
171
|
+
# @param _type [String] the type of image (e.g., 'external', 'file').
|
172
|
+
# @param options [Hash] additional options for rendering.
|
173
|
+
# @return [String] an HTML-safe string with the rendered image.
|
174
|
+
def render_image(src, _expiry_time, caption, _type, options = {})
|
175
|
+
content_tag(:figure, **options, class: css_class_for(:image, options)) do
|
176
|
+
content = tag.img(src: src, alt: '')
|
177
|
+
content += tag.figcaption(text_renderer(caption))
|
178
|
+
content
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Renders a numbered list item.
|
183
|
+
#
|
184
|
+
# @param rich_text_array [Array] the rich text array containing the content of the list item.
|
185
|
+
# @param siblings [Array] sibling list items.
|
186
|
+
# @param children [Array] child list items.
|
187
|
+
# @param options [Hash] additional options for rendering.
|
188
|
+
# @return [String] an HTML-safe string with the rendered list item.
|
189
|
+
def render_numbered_list_item(rich_text_array, siblings, children, parent_index, options = {})
|
190
|
+
content_tag(:ol, **options, class: css_class_for(:numbered_list_item, options)) do
|
191
|
+
render_list_items(:numbered_list_item, rich_text_array, siblings, children, parent_index, options)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Renders a paragraph block.
|
196
|
+
#
|
197
|
+
# @param rich_text_array [Array] the rich text array containing the content of the paragraph.
|
198
|
+
# @param options [Hash] additional options for rendering.
|
199
|
+
# @return [String] an HTML-safe string with the rendered paragraph.
|
200
|
+
def render_paragraph(rich_text_array, options = {})
|
201
|
+
content_tag(:p, **options, class: css_class_for(:paragraph, options)) do
|
202
|
+
text_renderer(rich_text_array)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# Renders a quote block.
|
207
|
+
#
|
208
|
+
# @param rich_text_array [Array] the rich text array containing the content of the quote.
|
209
|
+
# @param options [Hash] additional options for rendering.
|
210
|
+
# @return [String] an HTML-safe string with the rendered quote.
|
211
|
+
def render_quote(rich_text_array, options = {})
|
212
|
+
content_tag(:div, options) do
|
213
|
+
content_tag(:cite) do
|
214
|
+
content_tag(:p, **options, class: css_class_for(:quote, options)) do
|
215
|
+
text_renderer(rich_text_array)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Renders a table of contents block.
|
222
|
+
#
|
223
|
+
# @param options [Hash] additional options for rendering.
|
224
|
+
# @return [String] an HTML-safe string with the rendered table of contents.
|
225
|
+
def render_table_of_contents(options = {})
|
226
|
+
content_tag(:p, 'Table of Contents', class: css_class_for(:table_of_contents, options))
|
227
|
+
end
|
228
|
+
|
229
|
+
# Renders a video block.
|
230
|
+
#
|
231
|
+
# @param src [String] the source URL of the video.
|
232
|
+
# @param _expiry_time [Time] the expiration time of the video.
|
233
|
+
# @param caption [Array] the caption text array for the video.
|
234
|
+
# @param options [Hash] additional options for rendering.
|
235
|
+
# @return [String] an HTML-safe string with the rendered video.
|
236
|
+
def render_video(src, _expiry_time, caption, type, options = {})
|
237
|
+
content_tag(:figure, **options, class: css_class_for(:video, options)) do
|
238
|
+
content = if type == 'file'
|
239
|
+
video_tag(src, controls: true, **options, class: css_class_for(:video, options))
|
240
|
+
elsif type == 'external'
|
241
|
+
options[:class] = "#{options[:class]} aspect-video"
|
242
|
+
tag.iframe(src: src, allowfullscreen: true, **options, class: css_class_for(:video, options))
|
243
|
+
end
|
244
|
+
content += tag.figcaption(text_renderer(caption))
|
245
|
+
content
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
private
|
250
|
+
|
251
|
+
# Determines the CSS class for a given block type.
|
252
|
+
#
|
253
|
+
# @param type [Symbol] the block type (e.g., :paragraph, :heading_1, etc.).
|
254
|
+
# @param options [Hash] additional options for rendering.
|
255
|
+
# @return [String] the CSS class for the block.
|
256
|
+
def css_class_for(type, options)
|
257
|
+
if options[:override_class]
|
258
|
+
options[:class]
|
259
|
+
else
|
260
|
+
"#{DEFAULT_CSS_CLASSES[type]} #{options[:class]}".strip
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
# Renders list items (bulleted or numbered).
|
265
|
+
#
|
266
|
+
# @param list_type [Symbol] the type of list (:bulleted_list_item or :numbered_list_item).
|
267
|
+
# @param rich_text_array [Array] the rich text array containing the content of the list item.
|
268
|
+
# @param siblings [Array] sibling list items.
|
269
|
+
# @param children [Array] child list items.
|
270
|
+
# @param options [Hash] additional options for rendering.
|
271
|
+
# @return [String] an HTML-safe string with the rendered list items.
|
272
|
+
def render_list_items(type, rich_text_array, siblings, children, parent_index, options = {})
|
273
|
+
content = content_tag(:li, class: "#{options[:class]} ml-#{parent_index.to_i * 2}".strip) do
|
274
|
+
text_renderer(rich_text_array)
|
275
|
+
end
|
276
|
+
if children.present?
|
277
|
+
res = children.map do |child|
|
278
|
+
send("render_#{type}".to_sym, child.rich_text, child.siblings, child.children, parent_index.to_i + 1, options)
|
279
|
+
end
|
280
|
+
content += res.join('').html_safe
|
281
|
+
end
|
282
|
+
if siblings.present?
|
283
|
+
content += siblings.map do |sibling|
|
284
|
+
render_list_items(type, sibling.rich_text, sibling.siblings, sibling.children, parent_index.to_i, options)
|
285
|
+
end.join('').html_safe
|
286
|
+
end
|
287
|
+
content.html_safe
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'notion-ruby-client'
|
4
|
+
|
5
|
+
# The NotionToHtml::Service module is responsible for managing interactions with the Notion API, specifically for retrieving and processing pages and blocks.
|
6
|
+
# This module provides a set of methods that handle queries, sorting, and filtering based on tags, slugs, and other properties.
|
7
|
+
# It also manages the retrieval of page content, including associated blocks, and ensures that images are refreshed if their expiry time has passed.
|
8
|
+
|
9
|
+
module NotionToHtml
|
10
|
+
class Service
|
11
|
+
class << self
|
12
|
+
# Generates the default query for fetching pages
|
13
|
+
# @param tag [String, nil] The tag to filter pages by, or nil to include all tags
|
14
|
+
# @param slug [String, nil] The slug to filter pages by, or nil to include all slugs
|
15
|
+
# @return [Array<Hash>] The default query to be used in the database query
|
16
|
+
def default_query(tag: nil, slug: nil)
|
17
|
+
query = [
|
18
|
+
{
|
19
|
+
property: 'public',
|
20
|
+
checkbox: {
|
21
|
+
equals: true
|
22
|
+
}
|
23
|
+
}
|
24
|
+
]
|
25
|
+
|
26
|
+
if slug
|
27
|
+
query.push({
|
28
|
+
property: 'slug',
|
29
|
+
rich_text: {
|
30
|
+
equals: slug
|
31
|
+
}
|
32
|
+
})
|
33
|
+
end
|
34
|
+
|
35
|
+
if tag
|
36
|
+
query.push({
|
37
|
+
property: 'tags',
|
38
|
+
multi_select: {
|
39
|
+
contains: tag
|
40
|
+
}
|
41
|
+
})
|
42
|
+
end
|
43
|
+
|
44
|
+
query
|
45
|
+
end
|
46
|
+
|
47
|
+
# Provides the default sorting order for fetching pages
|
48
|
+
# @return [Hash] The default sorting criteria for database queries
|
49
|
+
def default_sorting
|
50
|
+
{
|
51
|
+
property: 'published',
|
52
|
+
direction: 'descending'
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
# Fetches a list of pages from Notion based on provided filters
|
57
|
+
# @param tag [String, nil] The tag to filter pages by, or nil to include all tags
|
58
|
+
# @param slug [String, nil] The slug to filter pages by, or nil to include all slugs
|
59
|
+
# @param page_size [Integer] The number of pages to fetch per page
|
60
|
+
# @return [Array<NotionToHtml::BasePage>] The list of pages as BasePage objects
|
61
|
+
def get_pages(tag: nil, slug: nil, page_size: 10)
|
62
|
+
__get_pages(tag: tag, slug: slug, page_size: page_size)['results'].map do |page|
|
63
|
+
NotionToHtml::BasePage.new(page)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Fetches a single page by its ID
|
68
|
+
# @param id [String] The ID of the page to fetch
|
69
|
+
# @return [NotionToHtml::Page] The page as a NotionToHtml::Page object
|
70
|
+
def get_page(id)
|
71
|
+
base_page = NotionToHtml::BasePage.new(__get_page(id))
|
72
|
+
base_blocks = get_blocks(id)
|
73
|
+
NotionToHtml::Page.new(base_page, base_blocks)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Fetches blocks associated with a given page ID
|
77
|
+
# @param id [String] The ID of the page whose blocks are to be fetched
|
78
|
+
# @return [Array<NotionToHtml::BaseBlock>] The list of blocks as BaseBlock objects
|
79
|
+
def get_blocks(id)
|
80
|
+
blocks = __get_blocks(id)
|
81
|
+
parent_list_block_index = nil
|
82
|
+
results = []
|
83
|
+
blocks['results'].each_with_index do |block, index|
|
84
|
+
block = refresh_block(block['id']) if refresh_image?(block)
|
85
|
+
base_block = NotionToHtml::BaseBlock.new(block)
|
86
|
+
base_block.children = get_blocks(base_block.id) if base_block.has_children
|
87
|
+
if %w[numbered_list_item].include? base_block.type
|
88
|
+
siblings = !parent_list_block_index.nil? &&
|
89
|
+
index != parent_list_block_index &&
|
90
|
+
base_block.type == results[parent_list_block_index]&.type &&
|
91
|
+
base_block.parent == results[parent_list_block_index]&.parent
|
92
|
+
if siblings
|
93
|
+
results[parent_list_block_index].siblings << base_block
|
94
|
+
next
|
95
|
+
else
|
96
|
+
parent_list_block_index = results.length
|
97
|
+
end
|
98
|
+
else
|
99
|
+
parent_list_block_index = nil
|
100
|
+
end
|
101
|
+
results << base_block
|
102
|
+
end
|
103
|
+
results
|
104
|
+
end
|
105
|
+
|
106
|
+
# Determines if an image block needs to be refreshed based on its expiry time
|
107
|
+
# @param data [Hash] The data of the image block
|
108
|
+
# @return [Boolean] True if the image needs to be refreshed, false otherwise
|
109
|
+
def refresh_image?(data)
|
110
|
+
return false unless data['type'] == 'image'
|
111
|
+
return false unless data.dig('image', 'type') == 'file'
|
112
|
+
|
113
|
+
expiry_time = data.dig('image', 'file', 'expiry_time')
|
114
|
+
expiry_time.to_datetime.past?
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
# Accessor for the client
|
120
|
+
# @return [Notion::Client] The client instance used to interact with the Notion API
|
121
|
+
def client
|
122
|
+
@client ||= Notion::Client.new(token: NotionToHtml.config.notion_api_token)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Retrieves pages from Notion using the client
|
126
|
+
# @param tag [String, nil] The tag to filter pages by
|
127
|
+
# @param slug [String, nil] The slug to filter pages by
|
128
|
+
# @param page_size [Integer] The number of pages to fetch per page
|
129
|
+
# @return [Hash] The response from the Notion API containing pages
|
130
|
+
def __get_pages(tag: nil, slug: nil, page_size: 10)
|
131
|
+
client.database_query(
|
132
|
+
database_id: NotionToHtml.config.notion_database_id,
|
133
|
+
sorts: [
|
134
|
+
default_sorting
|
135
|
+
],
|
136
|
+
filter: {
|
137
|
+
'and': default_query(tag: tag, slug: slug)
|
138
|
+
},
|
139
|
+
page_size: page_size
|
140
|
+
)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Retrieves a single page by its ID from Notion
|
144
|
+
# @param id [String] The ID of the page to fetch
|
145
|
+
# @return [Hash] The response from the Notion API containing the page
|
146
|
+
def __get_page(id)
|
147
|
+
client.page(page_id: id)
|
148
|
+
end
|
149
|
+
|
150
|
+
# Retrieves blocks associated with a given ID from Notion, using cache if available
|
151
|
+
# @param id [String] The ID of the block to fetch
|
152
|
+
# @return [Hash] The response from the Notion API containing the blocks
|
153
|
+
def __get_blocks(id)
|
154
|
+
NotionToHtml.config.cache_store.fetch(id) { client.block_children(block_id: id) }
|
155
|
+
end
|
156
|
+
|
157
|
+
# Retrieves a single block by its ID from Notion
|
158
|
+
# @param id [String] The ID of the block to fetch
|
159
|
+
# @return [Hash] The response from the Notion API containing the block
|
160
|
+
def __get_block(id)
|
161
|
+
client.block(block_id: id)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Refreshes a block by retrieving it again from Notion
|
165
|
+
# @param id [String] The ID of the block to refresh
|
166
|
+
# @return [Hash] The response from the Notion API containing the refreshed block
|
167
|
+
def refresh_block(id)
|
168
|
+
__get_block(id)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/all'
|
4
|
+
require 'notion_to_html/renderers'
|
5
|
+
require 'notion_to_html/base_block'
|
6
|
+
require 'notion_to_html/base_page'
|
7
|
+
require 'notion_to_html/page'
|
8
|
+
require 'notion_to_html/service'
|
9
|
+
require 'dry-configurable'
|
10
|
+
|
11
|
+
module NotionToHtml
|
12
|
+
extend Dry::Configurable
|
13
|
+
|
14
|
+
# @!attribute [rw] notion_api_token
|
15
|
+
# @return [String] The API token used to authenticate requests to the Notion API.
|
16
|
+
setting :notion_api_token
|
17
|
+
|
18
|
+
# @!attribute [rw] notion_database_id
|
19
|
+
# @return [String] The database ID in Notion that the module will interact with.
|
20
|
+
setting :notion_database_id
|
21
|
+
|
22
|
+
# @!attribute [rw] cache_store
|
23
|
+
# @return [ActiveSupport::Cache::Store] The cache store used to cache responses from the Notion API.
|
24
|
+
# @default ActiveSupport::Cache::MemoryStore.new
|
25
|
+
setting :cache_store, default: ActiveSupport::Cache::MemoryStore.new
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: notion_to_html
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Guillermo Aguirre
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-08-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: actionview
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '7'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 7.0.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '7'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 7.0.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: activesupport
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '7'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 7.0.0
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '7'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 7.0.0
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: dry-configurable
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '1.2'
|
60
|
+
type: :runtime
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - "~>"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '1.2'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: notion-ruby-client
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 1.2.2
|
74
|
+
type: :runtime
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 1.2.2
|
81
|
+
description: Simple gem to render Notion blocks as HTML using Ruby
|
82
|
+
email:
|
83
|
+
- guillermoaguirre@hey.com
|
84
|
+
executables: []
|
85
|
+
extensions: []
|
86
|
+
extra_rdoc_files: []
|
87
|
+
files:
|
88
|
+
- LICENSE.txt
|
89
|
+
- README.md
|
90
|
+
- lib/notion_to_html.rb
|
91
|
+
- lib/notion_to_html/base_block.rb
|
92
|
+
- lib/notion_to_html/base_page.rb
|
93
|
+
- lib/notion_to_html/page.rb
|
94
|
+
- lib/notion_to_html/renderers.rb
|
95
|
+
- lib/notion_to_html/service.rb
|
96
|
+
- lib/notion_to_html/version.rb
|
97
|
+
homepage: https://github.com/guillermoap/notion_to_html
|
98
|
+
licenses:
|
99
|
+
- MIT
|
100
|
+
metadata:
|
101
|
+
homepage_uri: https://github.com/guillermoap/notion_to_html
|
102
|
+
source_code_uri: https://github.com/guillermoap/notion_to_html
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options: []
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '3.1'
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
requirements: []
|
118
|
+
rubygems_version: 3.5.11
|
119
|
+
signing_key:
|
120
|
+
specification_version: 4
|
121
|
+
summary: Notion HTML renderer for Ruby
|
122
|
+
test_files: []
|