notion_to_html 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
![Database structure](/docs/images/database_structure.png)
|
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
|
+
![Create integration](/docs/images/new_integration.png)
|
75
|
+
2. Enter the integration name and select the associated workspace for the new integration.
|
76
|
+
![Select workspace](/docs/images/new_integration_select_workspace.png)
|
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
|
+
![API secret](/docs/images/get_api_key.png)
|
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
|
+
![alt text](/docs/images/permissions.gif)
|
96
|
+
6. You can then limit the integrations permission to just `Read Contents`:
|
97
|
+
![alt text](/docs/images/permissions.png)
|
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: []
|